Merge branch '4.0.x'

Closes gh-49732
This commit is contained in:
Phillip Webb
2026-03-24 13:43:06 -07:00
2 changed files with 31 additions and 15 deletions
@@ -17,7 +17,6 @@
package org.springframework.boot.context.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -201,22 +200,23 @@ class ConfigDataEnvironment {
private List<ConfigDataEnvironmentContributor> getInitialImportContributors(Binder binder) {
List<ConfigDataEnvironmentContributor> initialContributors = new ArrayList<>();
addInitialImportContributors(initialContributors, bindLocations(binder, IMPORT_PROPERTY, EMPTY_LOCATIONS));
addInitialImportContributors(initialContributors,
bindLocations(binder, ADDITIONAL_LOCATION_PROPERTY, EMPTY_LOCATIONS));
addInitialImportContributors(initialContributors,
bindLocations(binder, LOCATION_PROPERTY, DEFAULT_SEARCH_LOCATIONS));
addInitialImportContributors(initialContributors, binder, IMPORT_PROPERTY, EMPTY_LOCATIONS, false);
addInitialImportContributors(initialContributors, binder, ADDITIONAL_LOCATION_PROPERTY, EMPTY_LOCATIONS, true);
addInitialImportContributors(initialContributors, binder, LOCATION_PROPERTY, DEFAULT_SEARCH_LOCATIONS, true);
return initialContributors;
}
private ConfigDataLocation[] bindLocations(Binder binder, String propertyName, ConfigDataLocation[] other) {
return binder.bind(propertyName, CONFIG_DATA_LOCATION_ARRAY).orElse(other);
}
private void addInitialImportContributors(List<ConfigDataEnvironmentContributor> initialContributors,
ConfigDataLocation[] locations) {
addInitialImportContributors(initialContributors,
Arrays.stream(locations).filter(ConfigDataLocation::isNotEmpty).toList());
private void addInitialImportContributors(List<ConfigDataEnvironmentContributor> initialContributors, Binder binder,
String propertyName, ConfigDataLocation[] defaultValue, boolean registerIndividually) {
ConfigDataLocation[] locations = binder.bind(propertyName, CONFIG_DATA_LOCATION_ARRAY).orElse(defaultValue);
if (registerIndividually) {
for (int i = locations.length - 1; i >= 0; i--) {
addInitialImportContributors(initialContributors, List.of(locations[i]));
}
}
else {
addInitialImportContributors(initialContributors, List.of(locations));
}
}
private void addInitialImportContributors(List<ConfigDataEnvironmentContributor> initialContributors,
@@ -18,6 +18,8 @@ package org.springframework.boot.context.config;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
@@ -30,6 +32,7 @@ import org.assertj.core.api.InstanceOfAssertFactories;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -146,7 +149,7 @@ class ConfigDataEnvironmentTests {
.map(ConfigDataEnvironmentContributor::getImports)
.map(Object::toString)
.toArray();
assertThat(imports).containsExactly("[i1, i2]", "[a1, a2]", "[l1, l2]");
assertThat(imports).containsExactly("[i1, i2]", "[a2]", "[a1]", "[l2]", "[l1]");
}
@Test
@@ -382,6 +385,19 @@ class ConfigDataEnvironmentTests {
.containsOnly(SeparateClassLoaderConfigDataLoader.class);
}
@Test // gh-49724
@WithResource(name = "application-local.properties", content = "test.property=classpath-local")
void processAndApplyWhenExternalFileConfigOverridesProfileSpecificClasspathConfig(@TempDir Path tempDir)
throws IOException {
Files.writeString(tempDir.resolve("application.properties"), "test.property=file-default\n");
this.environment.setProperty("spring.config.location",
"optional:classpath:/,optional:file:" + tempDir.toAbsolutePath() + "/");
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, List.of("local"), null);
configDataEnvironment.processAndApply();
assertThat(this.environment.getProperty("test.property")).isEqualTo("file-default");
}
private String getConfigLocation(TestInfo info) {
return "optional:classpath:" + info.getTestClass().get().getName().replace('.', '/') + "-"
+ info.getTestMethod().get().getName() + ".properties";