From 32e1289bbcdc0c1bf8ff9a375600cb9f9277f73d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 10 Dec 2020 11:03:03 +0000 Subject: [PATCH] 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 --- .../config/StandardConfigDataLoader.java | 2 +- ...ironmentPostProcessorIntegrationTests.java | 19 +++++++++++++++---- .../config/StandardConfigDataLoaderTests.java | 10 ++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLoader.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLoader.java index bd8f730dfc84..eb8ad51bcc8d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLoader.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLoader.java @@ -40,7 +40,7 @@ public ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResour StandardConfigDataReference reference = resource.getReference(); Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(), 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()); List> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource); return new ConfigData(propertySources); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java index b321ef6f92c5..0741b280f5e0 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java @@ -383,8 +383,8 @@ void runWhenHasActiveProfileConfigurationInMultiDocumentFileLoadsInExpectedOrder List names = StreamSupport.stream(context.getEnvironment().getPropertySources().spliterator(), false) .map(org.springframework.core.env.PropertySource::getName).collect(Collectors.toList()); assertThat(names).contains( - "Config resource 'classpath: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 #0)", + "Config resource 'class path resource [configdata/profiles/testsetprofiles.yml]' via location 'classpath:configdata/profiles/' (document #1)"); } @Test @@ -411,7 +411,7 @@ void loadWhenHasConfigLocationAsFile() { String location = "file:src/test/resources/specificlocation.properties"; ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location); 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 @@ void loadWhenHasRelativeConfigLocationUsesFileLocation() { String location = "src/test/resources/specificlocation.properties"; ConfigurableApplicationContext context = this.application.run("--spring.config.location=" + location); 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 @@ -619,6 +620,16 @@ public Object onSuccess(ConfigurationPropertyName name, Bindable target, Bind 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 matchingPropertySource(final String sourceName) { return new Condition("environment containing property source " + sourceName) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java index ee69d6a545c5..e4f38fbb242a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java @@ -51,11 +51,13 @@ void loadWhenLocationResultsInMultiplePropertySourcesAddsAllToConfigData() throw assertThat(configData.getPropertySources().size()).isEqualTo(2); PropertySource source1 = configData.getPropertySources().get(0); PropertySource source2 = configData.getPropertySources().get(1); - assertThat(source1.getName()).isEqualTo("Config resource 'classpath:configdata/yaml/application.yml' " - + "via location 'classpath:configdata/yaml/application.yml' (document #0)"); + assertThat(source1.getName()) + .isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' " + + "via location 'classpath:configdata/yaml/application.yml' (document #0)"); assertThat(source1.getProperty("foo")).isEqualTo("bar"); - assertThat(source2.getName()).isEqualTo("Config resource 'classpath:configdata/yaml/application.yml' " - + "via location 'classpath:configdata/yaml/application.yml' (document #1)"); + assertThat(source2.getName()) + .isEqualTo("Config resource 'class path resource [configdata/yaml/application.yml]' " + + "via location 'classpath:configdata/yaml/application.yml' (document #1)"); assertThat(source2.getProperty("hello")).isEqualTo("world"); }