Use unique names for wildcard property sources

Update `StandardConfigDataLoader` to use unique names for property
sources imported from a wildcard location.

Prior to this commit, all the property sources created from the same
wildcard location would have the same name. Each time a property source
that is equal to an existing property source is added, it replaces the
existing property source. Property source equality is name-based so this
resulted in the last property sources from the wildcard location
winning.

This commit updates `StandardConfigDataLoader` to use the resolved
Resource rather than the wildcard location in which it was discovered
in the name of the property source that it creates, ensuring that each
is property source from a wildcard location is uniquely named.

Fixes gh-24428
pull/24453/head
Andy Wilkinson 4 years ago committed by Phillip Webb
parent aaaed07735
commit 32e1289bbc

@ -40,7 +40,7 @@ public class StandardConfigDataLoader implements ConfigDataLoader<StandardConfig
StandardConfigDataReference reference = resource.getReference(); StandardConfigDataReference reference = resource.getReference();
Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(), Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(),
Origin.from(reference.getConfigDataLocation())); Origin.from(reference.getConfigDataLocation()));
String name = String.format("Config resource '%s' via location '%s'", reference.getResourceLocation(), String name = String.format("Config resource '%s' via location '%s'", resource,
reference.getConfigDataLocation()); reference.getConfigDataLocation());
List<PropertySource<?>> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource); List<PropertySource<?>> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource);
return new ConfigData(propertySources); return new ConfigData(propertySources);

@ -383,8 +383,8 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
List<String> names = StreamSupport.stream(context.getEnvironment().getPropertySources().spliterator(), false) List<String> names = StreamSupport.stream(context.getEnvironment().getPropertySources().spliterator(), false)
.map(org.springframework.core.env.PropertySource::getName).collect(Collectors.toList()); .map(org.springframework.core.env.PropertySource::getName).collect(Collectors.toList());
assertThat(names).contains( assertThat(names).contains(
"Config resource 'classpath:configdata/profiles/testsetprofiles.yml' via location 'classpath:configdata/profiles/' (document #0)", "Config resource 'class path resource [configdata/profiles/testsetprofiles.yml]' via location 'classpath:configdata/profiles/' (document #0)",
"Config resource 'classpath:configdata/profiles/testsetprofiles.yml' via location 'classpath:configdata/profiles/' (document #1)"); "Config resource 'class path resource [configdata/profiles/testsetprofiles.yml]' via location 'classpath:configdata/profiles/' (document #1)");
} }
@Test @Test
@ -411,7 +411,7 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
String location = "file:src/test/resources/specificlocation.properties"; String location = "file:src/test/resources/specificlocation.properties";
ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location); ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location);
assertThat(context.getEnvironment()).has(matchingPropertySource( assertThat(context.getEnvironment()).has(matchingPropertySource(
"Config resource 'file:src/test/resources/specificlocation.properties' via location '" + location "Config resource 'file [src/test/resources/specificlocation.properties]' via location '" + location
+ "'")); + "'"));
} }
@ -420,7 +420,8 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
String location = "src/test/resources/specificlocation.properties"; String location = "src/test/resources/specificlocation.properties";
ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location); ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location);
assertThat(context.getEnvironment()).has(matchingPropertySource( assertThat(context.getEnvironment()).has(matchingPropertySource(
"Config resource 'src/test/resources/specificlocation.properties' via location '" + location + "'")); "Config resource 'file [src/test/resources/specificlocation.properties]' via location '" + location
+ "'"));
} }
@Test @Test
@ -619,6 +620,16 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
assertThat(origin.getParent().toString()).contains("application-import-with-placeholder"); assertThat(origin.getParent().toString()).contains("application-import-with-placeholder");
} }
@Test
void runWhenHasWildcardLocationLoadsFromAllMatchingLocations() {
ConfigurableApplicationContext context = this.application.run(
"--spring.config.location=optional:file:src/test/resources/config/*/",
"--spring.config.name=testproperties");
ConfigurableEnvironment environment = context.getEnvironment();
assertThat(environment.getProperty("first.property")).isEqualTo("apple");
assertThat(environment.getProperty("second.property")).isEqualTo("ball");
}
private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) { private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) { return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {

@ -51,10 +51,12 @@ public class StandardConfigDataLoaderTests {
assertThat(configData.getPropertySources().size()).isEqualTo(2); assertThat(configData.getPropertySources().size()).isEqualTo(2);
PropertySource<?> source1 = configData.getPropertySources().get(0); PropertySource<?> source1 = configData.getPropertySources().get(0);
PropertySource<?> source2 = configData.getPropertySources().get(1); PropertySource<?> source2 = configData.getPropertySources().get(1);
assertThat(source1.getName()).isEqualTo("Config resource 'classpath:configdata/yaml/application.yml' " assertThat(source1.getName())
.isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' "
+ "via location 'classpath:configdata/yaml/application.yml' (document #0)"); + "via location 'classpath:configdata/yaml/application.yml' (document #0)");
assertThat(source1.getProperty("foo")).isEqualTo("bar"); assertThat(source1.getProperty("foo")).isEqualTo("bar");
assertThat(source2.getName()).isEqualTo("Config resource 'classpath:configdata/yaml/application.yml' " assertThat(source2.getName())
.isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' "
+ "via location 'classpath:configdata/yaml/application.yml' (document #1)"); + "via location 'classpath:configdata/yaml/application.yml' (document #1)");
assertThat(source2.getProperty("hello")).isEqualTo("world"); assertThat(source2.getProperty("hello")).isEqualTo("world");
} }

Loading…
Cancel
Save