Merge branch '2.4.x'

Closes gh-24505
This commit is contained in:
Phillip Webb 2020-12-14 20:40:35 -08:00
commit 315067b379
8 changed files with 74 additions and 19 deletions

View File

@ -45,6 +45,11 @@ public final class ConfigData {
private final Set<Option> options;
/**
* A {@link ConfigData} instance that contains no data.
*/
public static final ConfigData EMPTY = new ConfigData(Collections.emptySet());
/**
* Create a new {@link ConfigData} instance.
* @param propertySources the config data property sources in ascending priority

View File

@ -300,6 +300,15 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
configurationPropertySource, null, ignoreImports, null);
}
/**
* Factory method to create an {@link Kind#EMPTY_LOCATION empty location} contributor.
* @param location the location of this contributor
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location) {
return new ConfigDataEnvironmentContributor(Kind.EMPTY_LOCATION, location, null, null, null, null, true, null);
}
/**
* The various kinds of contributor.
*/
@ -330,7 +339,12 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* A contributor with {@link ConfigData} imported from another contributor that
* has been.
*/
BOUND_IMPORT;
BOUND_IMPORT,
/**
* A valid location that contained noething to load.
*/
EMPTY_LOCATION;
}

View File

@ -161,10 +161,15 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
Map<ConfigDataResolutionResult, ConfigData> imported) {
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(imported.size() * 5);
imported.forEach((resolutionResult, data) -> {
for (int i = data.getPropertySources().size() - 1; i >= 0; i--) {
ConfigDataLocation location = resolutionResult.getLocation();
ConfigDataResource resource = resolutionResult.getResource();
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource, data, i));
ConfigDataLocation location = resolutionResult.getLocation();
ConfigDataResource resource = resolutionResult.getResource();
if (data.getPropertySources().isEmpty()) {
contributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location));
}
else {
for (int i = data.getPropertySources().size() - 1; i >= 0; i--) {
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource, data, i));
}
}
});
return Collections.unmodifiableList(contributors);

View File

@ -36,6 +36,9 @@ public class StandardConfigDataLoader implements ConfigDataLoader<StandardConfig
@Override
public ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResource resource)
throws IOException, ConfigDataNotFoundException {
if (resource.isEmptyDirectory()) {
return ConfigData.EMPTY;
}
ConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, resource.getResource());
StandardConfigDataReference reference = resource.getReference();
Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(),

View File

@ -17,6 +17,7 @@
package org.springframework.boot.context.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@ -220,25 +221,26 @@ public class StandardConfigDataLocationResolver
resolved.addAll(resolve(reference));
}
if (resolved.isEmpty()) {
assertNonOptionalDirectories(references);
resolved.addAll(resolveEmptyDirectories(references));
}
return resolved;
}
private void assertNonOptionalDirectories(Set<StandardConfigDataReference> references) {
private Collection<StandardConfigDataResource> resolveEmptyDirectories(
Set<StandardConfigDataReference> references) {
Set<StandardConfigDataResource> empty = new LinkedHashSet<>();
for (StandardConfigDataReference reference : references) {
if (reference.isNonOptionalDirectory()) {
assertDirectoryExists(reference);
if (reference.isMandatoryDirectory()) {
Resource resource = this.resourceLoader.getResource(reference.getDirectory());
if (resource instanceof ClassPathResource) {
continue;
}
StandardConfigDataResource configDataResource = new StandardConfigDataResource(reference, resource);
ConfigDataResourceNotFoundException.throwIfDoesNotExist(configDataResource, resource);
empty.add(new StandardConfigDataResource(reference, resource, true));
}
}
}
private void assertDirectoryExists(StandardConfigDataReference reference) {
Resource resource = this.resourceLoader.getResource(reference.getDirectory());
if (!(resource instanceof ClassPathResource)) {
StandardConfigDataResource configDataResource = new StandardConfigDataResource(reference, resource);
ConfigDataResourceNotFoundException.throwIfDoesNotExist(configDataResource, resource);
}
return empty;
}
private List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) {

View File

@ -66,7 +66,7 @@ class StandardConfigDataReference {
return this.resourceLocation;
}
boolean isNonOptionalDirectory() {
boolean isMandatoryDirectory() {
return !this.configDataLocation.isOptional() && this.directory != null;
}

View File

@ -36,16 +36,29 @@ public class StandardConfigDataResource extends ConfigDataResource {
private final Resource resource;
private boolean emptyDirectory;
/**
* Create a new {@link StandardConfigDataResource} instance.
* @param reference the resource reference
* @param resource the underlying resource
*/
StandardConfigDataResource(StandardConfigDataReference reference, Resource resource) {
this(reference, resource, false);
}
/**
* Create a new {@link StandardConfigDataResource} instance.
* @param reference the resource reference
* @param resource the underlying resource
* @param emptyDirectory if the resource is an empty directory that we know exists
*/
StandardConfigDataResource(StandardConfigDataReference reference, Resource resource, boolean emptyDirectory) {
Assert.notNull(reference, "Reference must not be null");
Assert.notNull(resource, "Resource must not be null");
this.reference = reference;
this.resource = resource;
this.emptyDirectory = emptyDirectory;
}
StandardConfigDataReference getReference() {
@ -56,6 +69,10 @@ public class StandardConfigDataResource extends ConfigDataResource {
return this.resource;
}
boolean isEmptyDirectory() {
return this.emptyDirectory;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
@ -65,7 +82,7 @@ public class StandardConfigDataResource extends ConfigDataResource {
return false;
}
StandardConfigDataResource other = (StandardConfigDataResource) obj;
return this.resource.equals(other.resource);
return this.resource.equals(other.resource) && this.emptyDirectory == other.emptyDirectory;
}
@Override

View File

@ -61,6 +61,7 @@ import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNoException;
/**
* Integration tests for {@link ConfigDataEnvironmentPostProcessor}.
@ -535,6 +536,14 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests {
.isThrownBy(() -> this.application.run("--spring.config.location=" + location));
}
@Test
void runWhenConfigLocationHasNonOptionalEmptyFileDirectoryDoesNotThrowException() {
File location = new File(this.temp, "application.empty");
location.mkdirs();
assertThatNoException().isThrownBy(() -> this.application
.run("--spring.config.location=" + StringUtils.cleanPath(location.getAbsolutePath()) + "/"));
}
@Test
@Disabled("Disabled until spring.profiles suppport is dropped")
void runWhenUsingInvalidPropertyThrowsException() {