Skip to content

Commit c45bb2b

Browse files
mbhavephilwebb
authored andcommitted
Handle empty locations from patterns
Update `StandardConfigDataLocationResolver` to deal with patterns when resolving empty directories. This update also fixes the handling of mandatory pattern locations which would previously throw an exception. The error message returned when a location with a pattern does not contain any subdirectories has also been improved. Fixes gh-26468 Fixes gh-26577 Fixes gh-26415
1 parent cfa2673 commit c45bb2b

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

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

+25-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayDeque;
2020
import java.util.ArrayList;
21+
import java.util.Arrays;
2122
import java.util.Collection;
2223
import java.util.Collections;
2324
import java.util.Deque;
@@ -26,6 +27,7 @@
2627
import java.util.Set;
2728
import java.util.regex.Matcher;
2829
import java.util.regex.Pattern;
30+
import java.util.stream.Collectors;
2931

3032
import org.apache.commons.logging.Log;
3133

@@ -243,19 +245,33 @@ private Collection<StandardConfigDataResource> resolveEmptyDirectories(
243245
Set<StandardConfigDataReference> references) {
244246
Set<StandardConfigDataResource> empty = new LinkedHashSet<>();
245247
for (StandardConfigDataReference reference : references) {
246-
if (reference.isMandatoryDirectory()) {
247-
Resource resource = this.resourceLoader.getResource(reference.getDirectory());
248-
if (resource instanceof ClassPathResource) {
249-
continue;
250-
}
251-
StandardConfigDataResource configDataResource = new StandardConfigDataResource(reference, resource);
252-
ConfigDataResourceNotFoundException.throwIfDoesNotExist(configDataResource, resource);
253-
empty.add(new StandardConfigDataResource(reference, resource, true));
254-
}
248+
empty.addAll(resolveEmptyDirectories(reference));
255249
}
256250
return empty;
257251
}
258252

253+
private Set<StandardConfigDataResource> resolveEmptyDirectories(StandardConfigDataReference reference) {
254+
if (!this.resourceLoader.isPattern(reference.getResourceLocation())) {
255+
return resolveNonPatternEmptyDirectories(reference);
256+
}
257+
return resolvePatternEmptyDirectories(reference);
258+
}
259+
260+
private Set<StandardConfigDataResource> resolveNonPatternEmptyDirectories(StandardConfigDataReference reference) {
261+
Resource resource = this.resourceLoader.getResource(reference.getDirectory());
262+
return (resource instanceof ClassPathResource || !resource.exists()) ? Collections.emptySet()
263+
: Collections.singleton(new StandardConfigDataResource(reference, resource, true));
264+
}
265+
266+
private Set<StandardConfigDataResource> resolvePatternEmptyDirectories(StandardConfigDataReference reference) {
267+
Resource[] resources = this.resourceLoader.getResources(reference.getDirectory(), ResourceType.DIRECTORY);
268+
Assert.state(resources.length > 0,
269+
"No subdirectories found for mandatory directory location '" + reference.getDirectory() + "'.");
270+
return Arrays.stream(resources).filter(Resource::exists)
271+
.map((resource) -> new StandardConfigDataResource(reference, resource, true))
272+
.collect(Collectors.toCollection(LinkedHashSet::new));
273+
}
274+
259275
private List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) {
260276
if (!this.resourceLoader.isPattern(reference.getResourceLocation())) {
261277
return resolveNonPattern(reference);

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

+28-3
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ void runWhenConfigLocationHasOptionalMissingDirectoryContinuesToLoad() {
547547
@Test
548548
void runWhenConfigLocationHasNonOptionalMissingFileDirectoryThrowsResourceNotFoundException() {
549549
File location = new File(this.temp, "application.unknown");
550-
assertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(() -> this.application
550+
assertThatExceptionOfType(ConfigDataLocationNotFoundException.class).isThrownBy(() -> this.application
551551
.run("--spring.config.location=" + StringUtils.cleanPath(location.getAbsolutePath()) + "/"));
552552
}
553553

@@ -566,6 +566,12 @@ void runWhenConfigLocationHasNonOptionalEmptyFileDirectoryDoesNotThrowException(
566566
.run("--spring.config.location=" + StringUtils.cleanPath(location.getAbsolutePath()) + "/"));
567567
}
568568

569+
@Test
570+
void runWhenConfigLocationHasMandatoryDirectoryThatDoesntExistThrowsException() {
571+
assertThatExceptionOfType(ConfigDataLocationNotFoundException.class).isThrownBy(
572+
() -> this.application.run("--spring.config.location=" + StringUtils.cleanPath("invalid/")));
573+
}
574+
569575
@Test
570576
void runWhenConfigLocationHasNonOptionalEmptyFileDoesNotThrowException() throws IOException {
571577
File location = new File(this.temp, "application.properties");
@@ -686,13 +692,32 @@ public Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, Bind
686692
@Test
687693
void runWhenHasWildcardLocationLoadsFromAllMatchingLocations() {
688694
ConfigurableApplicationContext context = this.application.run(
689-
"--spring.config.location=optional:file:src/test/resources/config/*/",
690-
"--spring.config.name=testproperties");
695+
"--spring.config.location=file:src/test/resources/config/*/", "--spring.config.name=testproperties");
691696
ConfigurableEnvironment environment = context.getEnvironment();
692697
assertThat(environment.getProperty("first.property")).isEqualTo("apple");
693698
assertThat(environment.getProperty("second.property")).isEqualTo("ball");
694699
}
695700

701+
@Test
702+
void runWhenMandatoryWildcardLocationHasEmptyFileDirectory() {
703+
assertThatNoException()
704+
.isThrownBy(() -> this.application.run("--spring.config.location=file:src/test/resources/config/*/"));
705+
}
706+
707+
@Test
708+
void runWhenMandatoryWildcardLocationHasNoSubdirectories() {
709+
assertThatIllegalStateException().isThrownBy(
710+
() -> this.application.run("--spring.config.location=file:src/test/resources/config/0-empty/*/"))
711+
.withMessage(
712+
"No subdirectories found for mandatory directory location 'file:src/test/resources/config/0-empty/*/'.");
713+
}
714+
715+
@Test
716+
void runWhenHasMandatoryWildcardLocationThatDoesNotExist() {
717+
assertThatExceptionOfType(ConfigDataLocationNotFoundException.class)
718+
.isThrownBy(() -> this.application.run("--spring.config.location=file:invalid/*/"));
719+
}
720+
696721
@Test // gh-24990
697722
void runWhenHasProfileSpecificFileWithActiveOnProfileProperty() {
698723
ConfigurableApplicationContext context = this.application

0 commit comments

Comments
 (0)