Browse Source

Refine non-optional classpath location checking

Update `StandardConfigDataLocationResolver` to no longer check if
directories exist for classpath resources. Unfortunately checking for
the parent directory of a `ClassPathResource` isn't always possible
without resorting something similar to the
`PathMatchingResourcePatternResolver` which would add a lot of
complexity to the resolver.

In order to ensure that non-optional locations are always resolved,
the `ConfigDataEnvironment` now checks that all imported locations
have been loaded.

Closes gh-24143
pull/24314/head
Phillip Webb 5 years ago
parent
commit
3dc03ac275
  1. 30
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java
  2. 39
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java
  3. 25
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java
  4. 8
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java
  5. 7
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLocationResolver.java
  6. 2
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java
  7. 30
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java
  8. 42
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java
  9. 16
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java

30
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java

@ -297,6 +297,7 @@ class ConfigDataEnvironment {
private void applyToEnvironment(ConfigDataEnvironmentContributors contributors, private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext) { ConfigDataActivationContext activationContext) {
checkForInvalidProperties(contributors); checkForInvalidProperties(contributors);
checkMandatoryLocations(contributors, activationContext);
MutablePropertySources propertySources = this.environment.getPropertySources(); MutablePropertySources propertySources = this.environment.getPropertySources();
this.logger.trace("Applying config data environment contributions"); this.logger.trace("Applying config data environment contributions");
for (ConfigDataEnvironmentContributor contributor : contributors) { for (ConfigDataEnvironmentContributor contributor : contributors) {
@ -327,4 +328,33 @@ class ConfigDataEnvironment {
} }
} }
private void checkMandatoryLocations(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext) {
Set<ConfigDataLocation> mandatoryLocations = new LinkedHashSet<>();
for (ConfigDataEnvironmentContributor contributor : contributors) {
mandatoryLocations.addAll(getMandatoryImports(contributor));
}
for (ConfigDataEnvironmentContributor contributor : contributors) {
if (contributor.getLocation() != null) {
mandatoryLocations.remove(contributor.getLocation());
}
}
if (!mandatoryLocations.isEmpty()) {
for (ConfigDataLocation mandatoryLocation : mandatoryLocations) {
this.notFoundAction.handle(this.logger, new ConfigDataLocationNotFoundException(mandatoryLocation));
}
}
}
private Set<ConfigDataLocation> getMandatoryImports(ConfigDataEnvironmentContributor contributor) {
List<ConfigDataLocation> imports = contributor.getImports();
Set<ConfigDataLocation> mandatoryLocations = new LinkedHashSet<>(imports.size());
for (ConfigDataLocation location : imports) {
if (!location.isOptional()) {
mandatoryLocations.add(location);
}
}
return mandatoryLocations;
}
} }

39
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java

@ -51,6 +51,8 @@ import org.springframework.core.env.PropertySource;
*/ */
class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironmentContributor> { class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironmentContributor> {
private final ConfigDataLocation location;
private final ConfigDataResource resource; private final ConfigDataResource resource;
private final PropertySource<?> propertySource; private final PropertySource<?> propertySource;
@ -68,6 +70,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
/** /**
* Create a new {@link ConfigDataEnvironmentContributor} instance. * Create a new {@link ConfigDataEnvironmentContributor} instance.
* @param kind the contributor kind * @param kind the contributor kind
* @param location the location of this contributor
* @param resource the resource that contributed the data or {@code null} * @param resource the resource that contributed the data or {@code null}
* @param propertySource the property source for the data or {@code null} * @param propertySource the property source for the data or {@code null}
* @param configurationPropertySource the configuration property source for the data * @param configurationPropertySource the configuration property source for the data
@ -76,10 +79,12 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* @param ignoreImports if import properties should be ignored * @param ignoreImports if import properties should be ignored
* @param children the children of this contributor at each {@link ImportPhase} * @param children the children of this contributor at each {@link ImportPhase}
*/ */
ConfigDataEnvironmentContributor(Kind kind, ConfigDataResource resource, PropertySource<?> propertySource, ConfigDataEnvironmentContributor(Kind kind, ConfigDataLocation location, ConfigDataResource resource,
ConfigurationPropertySource configurationPropertySource, ConfigDataProperties properties, PropertySource<?> propertySource, ConfigurationPropertySource configurationPropertySource,
boolean ignoreImports, Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children) { ConfigDataProperties properties, boolean ignoreImports,
Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children) {
this.kind = kind; this.kind = kind;
this.location = location;
this.resource = resource; this.resource = resource;
this.properties = properties; this.properties = properties;
this.propertySource = propertySource; this.propertySource = propertySource;
@ -96,6 +101,10 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
return this.kind; return this.kind;
} }
ConfigDataLocation getLocation() {
return this.location;
}
/** /**
* Return if this contributor is currently active. * Return if this contributor is currently active.
* @param activationContext the activation context * @param activationContext the activation context
@ -191,8 +200,8 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
if (this.ignoreImports) { if (this.ignoreImports) {
properties = properties.withoutImports(); properties = properties.withoutImports();
} }
return new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, this.resource, this.propertySource, return new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, this.location, this.resource,
this.configurationPropertySource, properties, this.ignoreImports, null); this.propertySource, this.configurationPropertySource, properties, this.ignoreImports, null);
} }
/** /**
@ -206,7 +215,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
List<ConfigDataEnvironmentContributor> children) { List<ConfigDataEnvironmentContributor> children) {
Map<ImportPhase, List<ConfigDataEnvironmentContributor>> updatedChildren = new LinkedHashMap<>(this.children); Map<ImportPhase, List<ConfigDataEnvironmentContributor>> updatedChildren = new LinkedHashMap<>(this.children);
updatedChildren.put(importPhase, children); updatedChildren.put(importPhase, children);
return new ConfigDataEnvironmentContributor(this.kind, this.resource, this.propertySource, return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.propertySource,
this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren); this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren);
} }
@ -231,7 +240,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
} }
updatedChildren.put(importPhase, Collections.unmodifiableList(updatedContributors)); updatedChildren.put(importPhase, Collections.unmodifiableList(updatedContributors));
}); });
return new ConfigDataEnvironmentContributor(this.kind, this.resource, this.propertySource, return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.propertySource,
this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren); this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren);
} }
@ -243,7 +252,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
static ConfigDataEnvironmentContributor of(List<ConfigDataEnvironmentContributor> contributors) { static ConfigDataEnvironmentContributor of(List<ConfigDataEnvironmentContributor> contributors) {
Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children = new LinkedHashMap<>(); Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children = new LinkedHashMap<>();
children.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.unmodifiableList(contributors)); children.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.unmodifiableList(contributors));
return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, null, null, false, children); return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, null, null, null, false, children);
} }
/** /**
@ -256,7 +265,8 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
static ConfigDataEnvironmentContributor ofInitialImport(ConfigDataLocation initialImport) { static ConfigDataEnvironmentContributor ofInitialImport(ConfigDataLocation initialImport) {
List<ConfigDataLocation> imports = Collections.singletonList(initialImport); List<ConfigDataLocation> imports = Collections.singletonList(initialImport);
ConfigDataProperties properties = new ConfigDataProperties(imports, null); ConfigDataProperties properties = new ConfigDataProperties(imports, null);
return new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, null, properties, false, null); return new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, null, null, properties, false,
null);
} }
/** /**
@ -267,7 +277,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* @return a new {@link ConfigDataEnvironmentContributor} instance * @return a new {@link ConfigDataEnvironmentContributor} instance
*/ */
static ConfigDataEnvironmentContributor ofExisting(PropertySource<?> propertySource) { static ConfigDataEnvironmentContributor ofExisting(PropertySource<?> propertySource) {
return new ConfigDataEnvironmentContributor(Kind.EXISTING, null, propertySource, return new ConfigDataEnvironmentContributor(Kind.EXISTING, null, null, propertySource,
ConfigurationPropertySource.from(propertySource), null, false, null); ConfigurationPropertySource.from(propertySource), null, false, null);
} }
@ -275,17 +285,18 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* Factory method to create an {@link Kind#UNBOUND_IMPORT unbound import} contributor. * Factory method to create an {@link Kind#UNBOUND_IMPORT unbound import} contributor.
* This contributor has been actively imported from another contributor and may itself * This contributor has been actively imported from another contributor and may itself
* import further contributors later. * import further contributors later.
* @param resource the condig data resource * @param location the location of this contributor
* @param resource the config data resource
* @param configData the config data * @param configData the config data
* @param propertySourceIndex the index of the property source that should be used * @param propertySourceIndex the index of the property source that should be used
* @return a new {@link ConfigDataEnvironmentContributor} instance * @return a new {@link ConfigDataEnvironmentContributor} instance
*/ */
static ConfigDataEnvironmentContributor ofUnboundImport(ConfigDataResource resource, ConfigData configData, static ConfigDataEnvironmentContributor ofUnboundImport(ConfigDataLocation location, ConfigDataResource resource,
int propertySourceIndex) { ConfigData configData, int propertySourceIndex) {
PropertySource<?> propertySource = configData.getPropertySources().get(propertySourceIndex); PropertySource<?> propertySource = configData.getPropertySources().get(propertySourceIndex);
ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource); ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource);
boolean ignoreImports = configData.getOptions().contains(ConfigData.Option.IGNORE_IMPORTS); boolean ignoreImports = configData.getOptions().contains(ConfigData.Option.IGNORE_IMPORTS);
return new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, resource, propertySource, return new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, location, resource, propertySource,
configurationPropertySource, null, ignoreImports, null); configurationPropertySource, null, ignoreImports, null);
} }

25
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java

@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -115,10 +116,9 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this); ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
List<ConfigDataLocation> imports = contributor.getImports(); List<ConfigDataLocation> imports = contributor.getImports();
this.logger.trace(LogMessage.format("Processing imports %s", imports)); this.logger.trace(LogMessage.format("Processing imports %s", imports));
Map<ConfigDataResource, ConfigData> imported = importer.resolveAndLoad(activationContext, Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext,
locationResolverContext, loaderContext, imports); locationResolverContext, loaderContext, imports);
this.logger.trace(LogMessage.of(() -> imported.isEmpty() ? "Nothing imported" : "Imported " this.logger.trace(LogMessage.of(() -> getImportedMessage(imported.keySet())));
+ imported.size() + " resource " + ((imported.size() != 1) ? "s" : "") + imported.keySet()));
ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase, ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase,
asContributors(imported)); asContributors(imported));
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
@ -127,6 +127,16 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
} }
} }
private CharSequence getImportedMessage(Set<ConfigDataResolutionResult> results) {
if (results.isEmpty()) {
return "Nothing imported";
}
StringBuilder message = new StringBuilder();
message.append("Imported " + results.size() + " resource" + ((results.size() != 1) ? "s " : " "));
message.append(results.stream().map(ConfigDataResolutionResult::getResource).collect(Collectors.toList()));
return message;
}
protected final ConfigurableBootstrapContext getBootstrapContext() { protected final ConfigurableBootstrapContext getBootstrapContext() {
return this.bootstrapContext; return this.bootstrapContext;
} }
@ -147,11 +157,14 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
return contributor.isActive(activationContext) && contributor.hasUnprocessedImports(importPhase); return contributor.isActive(activationContext) && contributor.hasUnprocessedImports(importPhase);
} }
private List<ConfigDataEnvironmentContributor> asContributors(Map<ConfigDataResource, ConfigData> imported) { private List<ConfigDataEnvironmentContributor> asContributors(
Map<ConfigDataResolutionResult, ConfigData> imported) {
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(imported.size() * 5); List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(imported.size() * 5);
imported.forEach((location, data) -> { imported.forEach((resolutionResult, data) -> {
for (int i = data.getPropertySources().size() - 1; i >= 0; i--) { for (int i = data.getPropertySources().size() - 1; i >= 0; i--) {
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, data, i)); ConfigDataLocation location = resolutionResult.getLocation();
ConfigDataResource resource = resolutionResult.getResource();
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource, data, i));
} }
}); });
return Collections.unmodifiableList(contributors); return Collections.unmodifiableList(contributors);

8
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java

@ -73,7 +73,7 @@ class ConfigDataImporter {
* @param locations the locations to resolve * @param locations the locations to resolve
* @return a map of the loaded locations and data * @return a map of the loaded locations and data
*/ */
Map<ConfigDataResource, ConfigData> resolveAndLoad(ConfigDataActivationContext activationContext, Map<ConfigDataResolutionResult, ConfigData> resolveAndLoad(ConfigDataActivationContext activationContext,
ConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext, ConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext,
List<ConfigDataLocation> locations) { List<ConfigDataLocation> locations) {
try { try {
@ -106,9 +106,9 @@ class ConfigDataImporter {
} }
} }
private Map<ConfigDataResource, ConfigData> load(ConfigDataLoaderContext loaderContext, private Map<ConfigDataResolutionResult, ConfigData> load(ConfigDataLoaderContext loaderContext,
List<ConfigDataResolutionResult> candidates) throws IOException { List<ConfigDataResolutionResult> candidates) throws IOException {
Map<ConfigDataResource, ConfigData> result = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> result = new LinkedHashMap<>();
for (int i = candidates.size() - 1; i >= 0; i--) { for (int i = candidates.size() - 1; i >= 0; i--) {
ConfigDataResolutionResult candidate = candidates.get(i); ConfigDataResolutionResult candidate = candidates.get(i);
ConfigDataLocation location = candidate.getLocation(); ConfigDataLocation location = candidate.getLocation();
@ -117,7 +117,7 @@ class ConfigDataImporter {
try { try {
ConfigData loaded = this.loaders.load(loaderContext, resource); ConfigData loaded = this.loaders.load(loaderContext, resource);
if (loaded != null) { if (loaded != null) {
result.put(resource, loaded); result.put(candidate, loaded);
} }
} }
catch (ConfigDataNotFoundException ex) { catch (ConfigDataNotFoundException ex) {

7
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLocationResolver.java

@ -31,6 +31,7 @@ import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.PropertySourceLoader; import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.io.support.SpringFactoriesLoader;
@ -234,8 +235,10 @@ public class StandardConfigDataLocationResolver
private void assertDirectoryExists(StandardConfigDataReference reference) { private void assertDirectoryExists(StandardConfigDataReference reference) {
Resource resource = this.resourceLoader.getResource(reference.getDirectory()); Resource resource = this.resourceLoader.getResource(reference.getDirectory());
StandardConfigDataResource configDataResource = new StandardConfigDataResource(reference, resource); if (!(resource instanceof ClassPathResource)) {
ConfigDataResourceNotFoundException.throwIfDoesNotExist(configDataResource, resource); StandardConfigDataResource configDataResource = new StandardConfigDataResource(reference, resource);
ConfigDataResourceNotFoundException.throwIfDoesNotExist(configDataResource, resource);
}
} }
private List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) { private List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) {

2
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java

@ -122,7 +122,7 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests {
private final boolean active; private final boolean active;
protected TestConfigDataEnvironmentContributor(PropertySource<?> propertySource, boolean active) { protected TestConfigDataEnvironmentContributor(PropertySource<?> propertySource, boolean active) {
super(Kind.ROOT, null, propertySource, null, null, false, null); super(Kind.ROOT, null, null, propertySource, null, null, false, null);
this.active = active; this.active = active;
} }

30
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java

@ -83,8 +83,8 @@ class ConfigDataEnvironmentContributorTests {
void getLocationReturnsLocation() { void getLocationReturnsLocation() {
ConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));
ConfigDataResource resource = mock(ConfigDataResource.class); ConfigDataResource resource = mock(ConfigDataResource.class);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(resource, ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
configData, 0); resource, configData, 0);
assertThat(contributor.getResource()).isSameAs(resource); assertThat(contributor.getResource()).isSameAs(resource);
} }
@ -100,7 +100,7 @@ class ConfigDataEnvironmentContributorTests {
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring", "boot"); propertySource.setProperty("spring", "boot");
ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigData configData = new ConfigData(Collections.singleton(propertySource));
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,
configData, 0); configData, 0);
assertThat(contributor.getConfigurationPropertySource() assertThat(contributor.getConfigurationPropertySource()
.getConfigurationProperty(ConfigurationPropertyName.of("spring")).getValue()).isEqualTo("boot"); .getConfigurationProperty(ConfigurationPropertyName.of("spring")).getValue()).isEqualTo("boot");
@ -279,14 +279,14 @@ class ConfigDataEnvironmentContributorTests {
@Test @Test
void ofUnboundImportCreatesImportedContributor() { void ofUnboundImportCreatesImportedContributor() {
TestResource location = new TestResource("test"); TestResource resource = new TestResource("test");
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.config.import", "test"); propertySource.setProperty("spring.config.import", "test");
ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigData configData = new ConfigData(Collections.singleton(propertySource));
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(location, ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
configData, 0); resource, configData, 0);
assertThat(contributor.getKind()).isEqualTo(Kind.UNBOUND_IMPORT); assertThat(contributor.getKind()).isEqualTo(Kind.UNBOUND_IMPORT);
assertThat(contributor.getResource()).isSameAs(location); assertThat(contributor.getResource()).isSameAs(resource);
assertThat(contributor.getImports()).isEmpty(); assertThat(contributor.getImports()).isEmpty();
assertThat(contributor.isActive(this.activationContext)).isTrue(); assertThat(contributor.isActive(this.activationContext)).isTrue();
assertThat(contributor.getPropertySource()).isEqualTo(propertySource); assertThat(contributor.getPropertySource()).isEqualTo(propertySource);
@ -296,13 +296,13 @@ class ConfigDataEnvironmentContributorTests {
@Test @Test
void bindCreatesImportedContributor() { void bindCreatesImportedContributor() {
TestResource location = new TestResource("test"); TestResource resource = new TestResource("test");
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.config.import", "test"); propertySource.setProperty("spring.config.import", "test");
ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigData configData = new ConfigData(Collections.singleton(propertySource));
ConfigDataEnvironmentContributor contributor = createBoundContributor(location, configData, 0); ConfigDataEnvironmentContributor contributor = createBoundContributor(resource, configData, 0);
assertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT); assertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT);
assertThat(contributor.getResource()).isSameAs(location); assertThat(contributor.getResource()).isSameAs(resource);
assertThat(contributor.getImports()).containsExactly(TEST_LOCATION); assertThat(contributor.getImports()).containsExactly(TEST_LOCATION);
assertThat(contributor.isActive(this.activationContext)).isTrue(); assertThat(contributor.isActive(this.activationContext)).isTrue();
assertThat(contributor.getPropertySource()).isEqualTo(propertySource); assertThat(contributor.getPropertySource()).isEqualTo(propertySource);
@ -312,13 +312,13 @@ class ConfigDataEnvironmentContributorTests {
@Test @Test
void bindWhenConfigDataHasIgnoreImportsOptionsCreatesImportedContributorWithoutImports() { void bindWhenConfigDataHasIgnoreImportsOptionsCreatesImportedContributorWithoutImports() {
TestResource location = new TestResource("test"); TestResource resource = new TestResource("test");
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.config.import", "test"); propertySource.setProperty("spring.config.import", "test");
ConfigData configData = new ConfigData(Collections.singleton(propertySource), ConfigData.Option.IGNORE_IMPORTS); ConfigData configData = new ConfigData(Collections.singleton(propertySource), ConfigData.Option.IGNORE_IMPORTS);
ConfigDataEnvironmentContributor contributor = createBoundContributor(location, configData, 0); ConfigDataEnvironmentContributor contributor = createBoundContributor(resource, configData, 0);
assertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT); assertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT);
assertThat(contributor.getResource()).isSameAs(location); assertThat(contributor.getResource()).isSameAs(resource);
assertThat(contributor.getImports()).isEmpty(); assertThat(contributor.getImports()).isEmpty();
assertThat(contributor.isActive(this.activationContext)).isTrue(); assertThat(contributor.isActive(this.activationContext)).isTrue();
assertThat(contributor.getPropertySource()).isEqualTo(propertySource); assertThat(contributor.getPropertySource()).isEqualTo(propertySource);
@ -341,8 +341,8 @@ class ConfigDataEnvironmentContributorTests {
private ConfigDataEnvironmentContributor createBoundContributor(ConfigDataResource resource, ConfigData configData, private ConfigDataEnvironmentContributor createBoundContributor(ConfigDataResource resource, ConfigData configData,
int propertySourceIndex) { int propertySourceIndex) {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(resource, ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
configData, propertySourceIndex); resource, configData, propertySourceIndex);
Binder binder = new Binder(contributor.getConfigurationPropertySource()); Binder binder = new Binder(contributor.getConfigurationPropertySource());
return contributor.withBoundProperties(binder); return contributor.withBoundProperties(binder);
} }

42
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java

@ -116,8 +116,9 @@ class ConfigDataEnvironmentContributorsTests {
this.importer = mock(ConfigDataImporter.class); this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> imported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new TestConfigDataResource("a"), new ConfigData(Arrays.asList(propertySource))); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")),
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)))
.willReturn(imported); .willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -138,14 +139,16 @@ class ConfigDataEnvironmentContributorsTests {
List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1);
MockPropertySource initialPropertySource = new MockPropertySource(); MockPropertySource initialPropertySource = new MockPropertySource();
initialPropertySource.setProperty("spring.config.import", "location2"); initialPropertySource.setProperty("spring.config.import", "location2");
Map<ConfigDataResource, ConfigData> initialImported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();
initialImported.put(new TestConfigDataResource("a"), new ConfigData(Arrays.asList(initialPropertySource))); initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")),
new ConfigData(Arrays.asList(initialPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))
.willReturn(initialImported); .willReturn(initialImported);
List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2); List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource(); MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> secondImported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();
secondImported.put(new TestConfigDataResource("b"), new ConfigData(Arrays.asList(secondPropertySource))); secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b")),
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)))
.willReturn(secondImported); .willReturn(secondImported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -170,8 +173,9 @@ class ConfigDataEnvironmentContributorsTests {
this.importer = mock(ConfigDataImporter.class); this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> imported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new TestConfigDataResource("a'"), new ConfigData(Arrays.asList(propertySource))); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")),
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)))
.willReturn(imported); .willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -189,14 +193,16 @@ class ConfigDataEnvironmentContributorsTests {
List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1);
MockPropertySource initialPropertySource = new MockPropertySource(); MockPropertySource initialPropertySource = new MockPropertySource();
initialPropertySource.setProperty("spring.config.import", "location2"); initialPropertySource.setProperty("spring.config.import", "location2");
Map<ConfigDataResource, ConfigData> initialImported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();
initialImported.put(new TestConfigDataResource("a"), new ConfigData(Arrays.asList(initialPropertySource))); initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")),
new ConfigData(Arrays.asList(initialPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))
.willReturn(initialImported); .willReturn(initialImported);
List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2); List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource(); MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> secondImported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();
secondImported.put(new TestConfigDataResource("b"), new ConfigData(Arrays.asList(secondPropertySource))); secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b")),
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)))
.willReturn(secondImported); .willReturn(secondImported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -217,8 +223,9 @@ class ConfigDataEnvironmentContributorsTests {
this.importer = mock(ConfigDataImporter.class); this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> imported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new TestConfigDataResource("a'"), new ConfigData(Arrays.asList(propertySource))); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")),
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)))
.willReturn(imported); .willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -239,8 +246,9 @@ class ConfigDataEnvironmentContributorsTests {
this.importer = mock(ConfigDataImporter.class); this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1); List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource(); MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResource, ConfigData> imported = new LinkedHashMap<>(); Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new TestConfigDataResource("a'"), new ConfigData(Arrays.asList(propertySource))); imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")),
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)))
.willReturn(imported); .willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
@ -377,7 +385,7 @@ class ConfigDataEnvironmentContributorsTests {
private ConfigDataEnvironmentContributor createBoundImportContributor(ConfigData configData, private ConfigDataEnvironmentContributor createBoundImportContributor(ConfigData configData,
int propertySourceIndex) { int propertySourceIndex) {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,
configData, propertySourceIndex); configData, propertySourceIndex);
Binder binder = new Binder(contributor.getConfigurationPropertySource()); Binder binder = new Binder(contributor.getConfigurationPropertySource());
return contributor.withBoundProperties(binder); return contributor.withBoundProperties(binder);

16
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java

@ -33,6 +33,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType; import org.springframework.boot.WebApplicationType;
@ -55,6 +56,7 @@ import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -70,6 +72,9 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
private SpringApplication application; private SpringApplication application;
@TempDir
public File temp;
@BeforeEach @BeforeEach
void setup() { void setup() {
this.application = new SpringApplication(Config.class); this.application = new SpringApplication(Config.class);
@ -516,9 +521,16 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
} }
@Test @Test
void runWhenConfigLocationHasNonOptionalMissingDirectoryThrowsException() { void runWhenConfigLocationHasNonOptionalMissingFileDirectoryThrowsResourceNotFoundException() {
File location = new File(this.temp, "application.unknown");
assertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(() -> this.application
.run("--spring.config.location=" + StringUtils.cleanPath(location.getAbsolutePath()) + "/"));
}
@Test
void runWhenConfigLocationHasNonOptionalMissingClasspathDirectoryThrowsLocationNotFoundException() {
String location = "classpath:application.unknown/"; String location = "classpath:application.unknown/";
assertThatExceptionOfType(ConfigDataResourceNotFoundException.class) assertThatExceptionOfType(ConfigDataLocationNotFoundException.class)
.isThrownBy(() -> this.application.run("--spring.config.location=" + location)); .isThrownBy(() -> this.application.run("--spring.config.location=" + location));
} }

Loading…
Cancel
Save