Skip to content

Commit

Permalink
Merge branch '2.4.x'
Browse files Browse the repository at this point in the history
Closes gh-26755
  • Loading branch information
philwebb committed Jun 4, 2021
2 parents 3c7a0d3 + 0da0d2d commit e73062a
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 48 deletions.
Expand Up @@ -328,6 +328,18 @@ private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
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();
Expand All @@ -345,13 +357,6 @@ private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
}
}
}
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) {
Expand Down
Expand Up @@ -117,9 +117,10 @@ ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter import
result, contributor, activationContext);
ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
List<ConfigDataLocation> imports = contributor.getImports();
boolean resolveProfileSpecific = !contributor.isFromProfileSpecificImport();
this.logger.trace(LogMessage.format("Processing imports %s", imports));
Map<ConfigDataResolutionResult, ConfigData> 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));
Expand Down
Expand Up @@ -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<ConfigDataResolutionResult, ConfigData> resolveAndLoad(ConfigDataActivationContext activationContext,
ConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext,
List<ConfigDataLocation> locations) {
List<ConfigDataLocation> locations, boolean resolveProfileSpecific) {
try {
Profiles profiles = (activationContext != null) ? activationContext.getProfiles() : null;
List<ConfigDataResolutionResult> resolved = resolve(locationResolverContext, profiles, locations);
List<ConfigDataResolutionResult> resolved = resolve(locationResolverContext, profiles, locations,
resolveProfileSpecific);
return load(loaderContext, resolved);
}
catch (IOException ex) {
Expand All @@ -91,18 +93,18 @@ Map<ConfigDataResolutionResult, ConfigData> resolveAndLoad(ConfigDataActivationC
}

private List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext locationResolverContext,
Profiles profiles, List<ConfigDataLocation> locations) {
Profiles profiles, List<ConfigDataLocation> locations, boolean resolveProfileSpecific) {
List<ConfigDataResolutionResult> 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<ConfigDataResolutionResult> 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);
Expand Down
Expand Up @@ -98,22 +98,23 @@ private List<ConfigDataLocationResolver<?>> reorder(List<ConfigDataLocationResol
}

List<ConfigDataResolutionResult> 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<ConfigDataResolutionResult> resolve(ConfigDataLocationResolver<?> resolver,
ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) {
ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles,
boolean resolveProfileSpecific) {
List<ConfigDataResolutionResult> resolved = resolve(location, false, () -> resolver.resolve(context, location));
if (profiles == null) {
if (profiles == null || !resolveProfileSpecific) {
return resolved;
}
List<ConfigDataResolutionResult> profileSpecific = resolve(location, true,
Expand Down
Expand Up @@ -44,6 +44,7 @@
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;
Expand Down Expand Up @@ -121,7 +122,7 @@ void withProcessedImportsResolvesAndLoads() {
Map<ConfigDataResolutionResult, ConfigData> 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,
Expand All @@ -144,14 +145,14 @@ void withProcessedImportsResolvesAndLoadsChainedImports() {
Map<ConfigDataResolutionResult, ConfigData> 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<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> 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,
Expand All @@ -178,13 +179,13 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToBinder() {
Map<ConfigDataResolutionResult, ConfigData> 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");
}
Expand All @@ -198,20 +199,21 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToParent() {
Map<ConfigDataResolutionResult, ConfigData> 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<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> 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");
}
Expand All @@ -228,13 +230,13 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToBootstrapReg
Map<ConfigDataResolutionResult, ConfigData> 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);
}
Expand All @@ -251,13 +253,13 @@ void withProcessedImportsProvidesLoaderContextWithAccessToBootstrapRegistry() {
Map<ConfigDataResolutionResult, ConfigData> 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);
}
Expand Down
Expand Up @@ -24,6 +24,7 @@
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;
Expand Down Expand Up @@ -59,6 +60,7 @@
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;
Expand Down Expand Up @@ -761,6 +763,15 @@ void runWhenHasProfileSpecificImportWithImportDoesNotImportSecondProfileSpecific
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<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {

Expand Down Expand Up @@ -798,7 +809,14 @@ public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDat
public List<TestConfigDataResource> resolve(ConfigDataLocationResolverContext context,
ConfigDataLocation location)
throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException {
return Collections.singletonList(new TestConfigDataResource(location));
return Collections.singletonList(new TestConfigDataResource(location, false));
}

@Override
public List<TestConfigDataResource> resolveProfileSpecific(ConfigDataLocationResolverContext context,
ConfigDataLocation location, org.springframework.boot.context.config.Profiles profiles)
throws ConfigDataLocationNotFoundException {
return Collections.singletonList(new TestConfigDataResource(location, true));
}

}
Expand All @@ -811,17 +829,55 @@ public ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource r
if (resource.isOptional()) {
return null;
}
MapPropertySource propertySource = new MapPropertySource("loaded",
Collections.singletonMap("spring", "boot"));
Map<String, Object> 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));
}

}

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();
}

}
Expand Down

0 comments on commit e73062a

Please sign in to comment.