From 0da0d2d4693779a91cd2e7c18ca4c3e567d4d633 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 3 Jun 2021 18:31:23 -0700 Subject: [PATCH] Prevent nested profile-specific resolution Update the `ConfigDataEnvironment` so that the `resolveProfileSpecific` method of `ConfigDataLocationResolver` is no longer called when resolving imports declared in a profile-specific file. Fixes gh-26753 --- .../context/config/ConfigDataEnvironment.java | 19 ++++-- .../ConfigDataEnvironmentContributors.java | 3 +- .../context/config/ConfigDataImporter.java | 14 ++-- .../config/ConfigDataLocationResolvers.java | 9 +-- ...onfigDataEnvironmentContributorsTests.java | 30 +++++---- ...ironmentPostProcessorIntegrationTests.java | 64 +++++++++++++++++-- .../config/ConfigDataImporterTests.java | 16 ++--- .../ConfigDataLocationResolversTests.java | 8 +-- ...ic-import-with-custom-import-p1.properties | 1 + ...cific-import-with-custom-import.properties | 2 + 10 files changed, 118 insertions(+), 48 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import-p1.properties create mode 100644 spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import.properties diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java index 0744d8a93b..2d449bdc22 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java @@ -328,6 +328,18 @@ class ConfigDataEnvironment { checkForInvalidProperties(contributors); checkMandatoryLocations(contributors, activationContext, loadedLocations, optionalLocations); MutablePropertySources propertySources = this.environment.getPropertySources(); + applyContributor(contributors, activationContext, propertySources); + DefaultPropertiesPropertySource.moveToEnd(propertySources); + Profiles profiles = activationContext.getProfiles(); + this.logger.trace(LogMessage.format("Setting default profiles: %s", profiles.getDefault())); + this.environment.setDefaultProfiles(StringUtils.toStringArray(profiles.getDefault())); + this.logger.trace(LogMessage.format("Setting active profiles: %s", profiles.getActive())); + this.environment.setActiveProfiles(StringUtils.toStringArray(profiles.getActive())); + this.environmentUpdateListener.onSetProfiles(profiles); + } + + private void applyContributor(ConfigDataEnvironmentContributors contributors, + ConfigDataActivationContext activationContext, MutablePropertySources propertySources) { this.logger.trace("Applying config data environment contributions"); for (ConfigDataEnvironmentContributor contributor : contributors) { PropertySource propertySource = contributor.getPropertySource(); @@ -345,13 +357,6 @@ class ConfigDataEnvironment { } } } - DefaultPropertiesPropertySource.moveToEnd(propertySources); - Profiles profiles = activationContext.getProfiles(); - this.logger.trace(LogMessage.format("Setting default profiles: %s", profiles.getDefault())); - this.environment.setDefaultProfiles(StringUtils.toStringArray(profiles.getDefault())); - this.logger.trace(LogMessage.format("Setting active profiles: %s", profiles.getActive())); - this.environment.setActiveProfiles(StringUtils.toStringArray(profiles.getActive())); - this.environmentUpdateListener.onSetProfiles(profiles); } private void checkForInvalidProperties(ConfigDataEnvironmentContributors contributors) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java index e40a4e46f4..1da7d5a8e4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java @@ -117,9 +117,10 @@ class ConfigDataEnvironmentContributors implements Iterable imports = contributor.getImports(); + boolean resolveProfileSpecific = !contributor.isFromProfileSpecificImport(); this.logger.trace(LogMessage.format("Processing imports %s", imports)); Map imported = importer.resolveAndLoad(activationContext, - locationResolverContext, loaderContext, imports); + locationResolverContext, loaderContext, imports, resolveProfileSpecific); this.logger.trace(LogMessage.of(() -> getImportedMessage(imported.keySet()))); ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase, asContributors(imported)); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java index 0970b4f6a6..4532c000b0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java @@ -75,14 +75,16 @@ class ConfigDataImporter { * @param locationResolverContext the location resolver context * @param loaderContext the loader context * @param locations the locations to resolve + * @param resolveProfileSpecific if profile specific resolution should be attempted * @return a map of the loaded locations and data */ Map resolveAndLoad(ConfigDataActivationContext activationContext, ConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext, - List locations) { + List locations, boolean resolveProfileSpecific) { try { Profiles profiles = (activationContext != null) ? activationContext.getProfiles() : null; - List resolved = resolve(locationResolverContext, profiles, locations); + List resolved = resolve(locationResolverContext, profiles, locations, + resolveProfileSpecific); return load(loaderContext, resolved); } catch (IOException ex) { @@ -91,18 +93,18 @@ class ConfigDataImporter { } private List resolve(ConfigDataLocationResolverContext locationResolverContext, - Profiles profiles, List locations) { + Profiles profiles, List locations, boolean resolveProfileSpecific) { List resolved = new ArrayList<>(locations.size()); for (ConfigDataLocation location : locations) { - resolved.addAll(resolve(locationResolverContext, profiles, location)); + resolved.addAll(resolve(locationResolverContext, profiles, location, resolveProfileSpecific)); } return Collections.unmodifiableList(resolved); } private List resolve(ConfigDataLocationResolverContext locationResolverContext, - Profiles profiles, ConfigDataLocation location) { + Profiles profiles, ConfigDataLocation location, boolean resolveProfileSpecific) { try { - return this.resolvers.resolve(locationResolverContext, location, profiles); + return this.resolvers.resolve(locationResolverContext, location, profiles, resolveProfileSpecific); } catch (ConfigDataNotFoundException ex) { handle(ex, location, null); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java index 5f89b1a0d8..55f5cb448e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java @@ -98,22 +98,23 @@ class ConfigDataLocationResolvers { } List resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location, - Profiles profiles) { + Profiles profiles, boolean resolveProfileSpecific) { if (location == null) { return Collections.emptyList(); } for (ConfigDataLocationResolver resolver : getResolvers()) { if (resolver.isResolvable(context, location)) { - return resolve(resolver, context, location, profiles); + return resolve(resolver, context, location, profiles, resolveProfileSpecific); } } throw new UnsupportedConfigDataLocationException(location); } private List resolve(ConfigDataLocationResolver resolver, - ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) { + ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles, + boolean resolveProfileSpecific) { List resolved = resolve(location, false, () -> resolver.resolve(context, location)); - if (profiles == null) { + if (profiles == null || !resolveProfileSpecific) { return resolved; } List profileSpecific = resolve(location, true, diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java index 54ca2020c0..e9b37306ab 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java @@ -43,6 +43,7 @@ import org.springframework.mock.env.MockPropertySource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -119,7 +120,7 @@ class ConfigDataEnvironmentContributorsTests { Map imported = new LinkedHashMap<>(); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(propertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations), anyBoolean())) .willReturn(imported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, @@ -142,14 +143,14 @@ class ConfigDataEnvironmentContributorsTests { Map initialImported = new LinkedHashMap<>(); initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(initialPropertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) - .willReturn(initialImported); + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations), + anyBoolean())).willReturn(initialImported); List secondLocations = Arrays.asList(LOCATION_2); MockPropertySource secondPropertySource = new MockPropertySource(); Map secondImported = new LinkedHashMap<>(); secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false), new ConfigData(Arrays.asList(secondPropertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations), anyBoolean())) .willReturn(secondImported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, @@ -176,13 +177,13 @@ class ConfigDataEnvironmentContributorsTests { Map imported = new LinkedHashMap<>(); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations), anyBoolean())) .willReturn(imported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, Arrays.asList(existingContributor, contributor)); contributors.withProcessedImports(this.importer, this.activationContext); - verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), any()); + verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), any(), anyBoolean()); ConfigDataLocationResolverContext context = this.locationResolverContext.getValue(); assertThat(context.getBinder().bind("test", String.class).get()).isEqualTo("springboot"); } @@ -196,20 +197,21 @@ class ConfigDataEnvironmentContributorsTests { Map initialImported = new LinkedHashMap<>(); initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(initialPropertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) - .willReturn(initialImported); + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations), + anyBoolean())).willReturn(initialImported); List secondLocations = Arrays.asList(LOCATION_2); MockPropertySource secondPropertySource = new MockPropertySource(); Map secondImported = new LinkedHashMap<>(); secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false), new ConfigData(Arrays.asList(secondPropertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations), anyBoolean())) .willReturn(secondImported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, Arrays.asList(contributor)); contributors.withProcessedImports(this.importer, this.activationContext); - verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), eq(secondLocations)); + verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), eq(secondLocations), + anyBoolean()); ConfigDataLocationResolverContext context = this.locationResolverContext.getValue(); assertThat(context.getParent()).hasToString("a"); } @@ -226,13 +228,13 @@ class ConfigDataEnvironmentContributorsTests { Map imported = new LinkedHashMap<>(); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations), anyBoolean())) .willReturn(imported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, Arrays.asList(existingContributor, contributor)); contributors.withProcessedImports(this.importer, this.activationContext); - verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), any()); + verify(this.importer).resolveAndLoad(any(), this.locationResolverContext.capture(), any(), any(), anyBoolean()); ConfigDataLocationResolverContext context = this.locationResolverContext.getValue(); assertThat(context.getBootstrapContext()).isSameAs(this.bootstrapContext); } @@ -249,13 +251,13 @@ class ConfigDataEnvironmentContributorsTests { Map imported = new LinkedHashMap<>(); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); - given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) + given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations), anyBoolean())) .willReturn(imported); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, Arrays.asList(existingContributor, contributor)); contributors.withProcessedImports(this.importer, this.activationContext); - verify(this.importer).resolveAndLoad(any(), any(), this.loaderContext.capture(), any()); + verify(this.importer).resolveAndLoad(any(), any(), this.loaderContext.capture(), any(), anyBoolean()); ConfigDataLoaderContext context = this.loaderContext.getValue(); assertThat(context.getBootstrapContext()).isSameAs(this.bootstrapContext); } 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 50eed302eb..3fce4eb875 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 @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; @@ -59,6 +60,7 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.FileCopyUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -761,6 +763,15 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { assertThat(environment.containsProperty("application-profile-specific-import-with-import-import-p2")).isFalse(); } + @Test // gh-26753 + void runWhenHasProfileSpecificImportWithCustomImportDoesNotResolveProfileSpecific() { + ConfigurableApplicationContext context = this.application + .run("--spring.config.name=application-profile-specific-import-with-custom-import"); + ConfigurableEnvironment environment = context.getEnvironment(); + assertThat(environment.containsProperty("test:boot")).isTrue(); + assertThat(environment.containsProperty("test:boot:ps")).isFalse(); + } + private Condition matchingPropertySource(final String sourceName) { return new Condition("environment containing property source " + sourceName) { @@ -798,7 +809,14 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { public List resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException { - return Collections.singletonList(new TestConfigDataResource(location)); + return Collections.singletonList(new TestConfigDataResource(location, false)); + } + + @Override + public List resolveProfileSpecific(ConfigDataLocationResolverContext context, + ConfigDataLocation location, org.springframework.boot.context.config.Profiles profiles) + throws ConfigDataLocationNotFoundException { + return Collections.singletonList(new TestConfigDataResource(location, true)); } } @@ -811,8 +829,13 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { if (resource.isOptional()) { return null; } - MapPropertySource propertySource = new MapPropertySource("loaded", - Collections.singletonMap("spring", "boot")); + Map map = new LinkedHashMap<>(); + if (!resource.isProfileSpecific()) { + map.put("spring", "boot"); + } + String suffix = (!resource.isProfileSpecific()) ? "" : ":ps"; + map.put(resource.toString() + suffix, "true"); + MapPropertySource propertySource = new MapPropertySource("loaded" + suffix, map); return new ConfigData(Collections.singleton(propertySource)); } @@ -820,8 +843,41 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { static class TestConfigDataResource extends ConfigDataResource { - TestConfigDataResource(ConfigDataLocation location) { + private final ConfigDataLocation location; + + private boolean profileSpecific; + + TestConfigDataResource(ConfigDataLocation location, boolean profileSpecific) { super(location.toString().contains("optionalresult")); + this.location = location; + this.profileSpecific = profileSpecific; + } + + boolean isProfileSpecific() { + return this.profileSpecific; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + TestConfigDataResource other = (TestConfigDataResource) obj; + return ObjectUtils.nullSafeEquals(this.location, other.location) + && this.profileSpecific == other.profileSpecific; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return this.location.toString(); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java index 73082f3f6a..ffd9bfbdf4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java @@ -80,16 +80,16 @@ class ConfigDataImporterTests { TestResource resource2 = new TestResource("r2"); ConfigData configData1 = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource())); - given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles)) + given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles, true)) .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false))); - given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles)) + given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles, true)) .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false))); given(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1); given(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2); ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL, this.resolvers, this.loaders); Collection loaded = importer.resolveAndLoad(this.activationContext, this.locationResolverContext, - this.loaderContext, Arrays.asList(location1, location2)).values(); + this.loaderContext, Arrays.asList(location1, location2), true).values(); assertThat(loaded).containsExactly(configData2, configData1); } @@ -106,11 +106,11 @@ class ConfigDataImporterTests { ConfigData configData1 = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData3 = new ConfigData(Collections.singleton(new MockPropertySource())); - given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles)) + given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles, true)) .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false))); - given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles)) + given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles, true)) .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false))); - given(this.resolvers.resolve(this.locationResolverContext, location3, this.profiles)) + given(this.resolvers.resolve(this.locationResolverContext, location3, this.profiles, true)) .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location3, resource3, false))); given(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1); given(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2); @@ -118,9 +118,9 @@ class ConfigDataImporterTests { ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL, this.resolvers, this.loaders); Collection loaded1and2 = importer.resolveAndLoad(this.activationContext, - this.locationResolverContext, this.loaderContext, locations1and2).values(); + this.locationResolverContext, this.loaderContext, locations1and2, true).values(); Collection loaded2and3 = importer.resolveAndLoad(this.activationContext, - this.locationResolverContext, this.loaderContext, locations2and3).values(); + this.locationResolverContext, this.loaderContext, locations2and3, true).values(); assertThat(loaded1and2).containsExactly(configData2, configData1); assertThat(loaded2and3).containsExactly(configData3); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java index 354e8a25d2..65eb86ac02 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java @@ -131,7 +131,7 @@ class ConfigDataLocationResolversTests { this.binder, this.resourceLoader, Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName())); ConfigDataLocation location = ConfigDataLocation.of("LowestTestResolver:test"); - List resolved = resolvers.resolve(this.context, location, null); + List resolved = resolvers.resolve(this.context, location, null, true); assertThat(resolved).hasSize(1); TestConfigDataResource resource = (TestConfigDataResource) resolved.get(0).getResource(); assertThat(resource.getResolver()).isInstanceOf(LowestTestResolver.class); @@ -145,7 +145,7 @@ class ConfigDataLocationResolversTests { this.binder, this.resourceLoader, Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName())); ConfigDataLocation location = ConfigDataLocation.of("LowestTestResolver:test"); - List resolved = resolvers.resolve(this.context, location, this.profiles); + List resolved = resolvers.resolve(this.context, location, this.profiles, true); assertThat(resolved).hasSize(2); TestConfigDataResource resource = (TestConfigDataResource) resolved.get(0).getResource(); assertThat(resource.getResolver()).isInstanceOf(LowestTestResolver.class); @@ -164,7 +164,7 @@ class ConfigDataLocationResolversTests { Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName())); ConfigDataLocation location = ConfigDataLocation.of("Missing:test"); assertThatExceptionOfType(UnsupportedConfigDataLocationException.class) - .isThrownBy(() -> resolvers.resolve(this.context, location, null)) + .isThrownBy(() -> resolvers.resolve(this.context, location, null, true)) .satisfies((ex) -> assertThat(ex.getLocation()).isEqualTo(location)); } @@ -173,7 +173,7 @@ class ConfigDataLocationResolversTests { ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext, this.binder, this.resourceLoader, Arrays.asList(OptionalResourceTestResolver.class.getName())); ConfigDataLocation location = ConfigDataLocation.of("OptionalResourceTestResolver:test"); - List resolved = resolvers.resolve(this.context, location, null); + List resolved = resolvers.resolve(this.context, location, null, true); assertThat(resolved.get(0).getResource().isOptional()).isTrue(); } diff --git a/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import-p1.properties b/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import-p1.properties new file mode 100644 index 0000000000..0457702de8 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import-p1.properties @@ -0,0 +1 @@ +spring.config.import:test:boot \ No newline at end of file diff --git a/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import.properties b/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import.properties new file mode 100644 index 0000000000..692617a894 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/application-profile-specific-import-with-custom-import.properties @@ -0,0 +1,2 @@ +spring.profiles.active=p1,p2 +