From c3fca0a826416239c63c898e76c24876de5b86bd Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 31 Oct 2022 14:20:45 +0100 Subject: [PATCH] Always register root directory for registered resource hints See gh-29403 --- ...lassPostProcessorAotContributionTests.java | 1 + .../aot/hint/ResourcePatternHints.java | 15 +++----- .../aot/hint/ResourceHintsTests.java | 35 ++++++++++++------- .../aot/hint/RuntimeHintsTests.java | 2 +- ...ilePatternResourceHintsRegistrarTests.java | 6 ++-- .../FileNativeConfigurationWriterTests.java | 1 + .../aot/nativex/ResourceHintsWriterTests.java | 6 ++++ 7 files changed, 39 insertions(+), 27 deletions(-) diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java index 89d0c82f3f98..80a784c1b007 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java @@ -150,6 +150,7 @@ void applyToWhenHasImportAwareConfigurationRegistersHints() { .satisfies(resourceHint -> assertThat(resourceHint.getIncludes()) .map(ResourcePatternHint::getPattern) .containsExactlyInAnyOrder( + "/", "org", "org/springframework", "org/springframework/context", diff --git a/spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHints.java b/spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHints.java index b3480cdb5981..876f6a3fe9f0 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHints.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHints.java @@ -98,20 +98,15 @@ public Builder includes(@Nullable TypeReference reachableType, String... include * @see gh-29403 */ private List expandToIncludeDirectories(String includePattern) { - // Root resource or no explicit subdirectories? + // Resource in root or no explicit subdirectories? if (!includePattern.contains("/")) { - if (includePattern.contains("*")) { - // If it's a root pattern, include the root directory as well as the pattern - return List.of("/", includePattern); - } - else { - // Include only the root resource - return List.of(includePattern); - } + // Include the root directory as well as the pattern + return List.of("/", includePattern); } List includePatterns = new ArrayList<>(); - // Ensure the original pattern is always included + // Ensure the root directory and original pattern are always included + includePatterns.add("/"); includePatterns.add(includePattern); StringBuilder path = new StringBuilder(); for (String pathElement : includePattern.split("/")) { diff --git a/spring-core/src/test/java/org/springframework/aot/hint/ResourceHintsTests.java b/spring-core/src/test/java/org/springframework/aot/hint/ResourceHintsTests.java index 5d9901401c7f..ba19adea625c 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/ResourceHintsTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/ResourceHintsTests.java @@ -46,14 +46,14 @@ class ResourceHintsTests { void registerType() { this.resourceHints.registerType(String.class); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("java", "java/lang", "java/lang/String.class")); + patternOf("/", "java", "java/lang", "java/lang/String.class")); } @Test void registerTypeWithNestedType() { this.resourceHints.registerType(TypeReference.of(Nested.class)); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", + patternOf("/", "org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", "org/springframework/aot/hint/ResourceHintsTests$Nested.class")); } @@ -61,7 +61,7 @@ void registerTypeWithNestedType() { void registerTypeWithInnerNestedType() { this.resourceHints.registerType(TypeReference.of(Inner.class)); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", + patternOf("/", "org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", "org/springframework/aot/hint/ResourceHintsTests$Nested$Inner.class")); } @@ -70,7 +70,7 @@ void registerTypeSeveralTimesAddsOnlyOneEntry() { this.resourceHints.registerType(String.class); this.resourceHints.registerType(TypeReference.of(String.class)); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("java", "java/lang", "java/lang/String.class")); + patternOf("/", "java", "java/lang", "java/lang/String.class")); } @Test @@ -78,8 +78,18 @@ void registerExactMatches() { this.resourceHints.registerPattern("com/example/test.properties"); this.resourceHints.registerPattern("com/example/another.properties"); assertThat(this.resourceHints.resourcePatternHints()) - .anySatisfy(patternOf("com", "com/example", "com/example/test.properties")) - .anySatisfy(patternOf("com", "com/example", "com/example/another.properties")) + .anySatisfy(patternOf("/", "com", "com/example", "com/example/test.properties")) + .anySatisfy(patternOf("/", "com", "com/example", "com/example/another.properties")) + .hasSize(2); + } + + @Test + void registerExactMatchesInRootDirectory() { + this.resourceHints.registerPattern("test.properties"); + this.resourceHints.registerPattern("another.properties"); + assertThat(this.resourceHints.resourcePatternHints()) + .anySatisfy(patternOf("/", "test.properties")) + .anySatisfy(patternOf("/", "another.properties")) .hasSize(2); } @@ -101,7 +111,7 @@ void registerRootPattern() { void registerPattern() { this.resourceHints.registerPattern("com/example/*.properties"); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("com", "com/example", "com/example/*.properties")); + patternOf("/", "com", "com/example", "com/example/*.properties")); } @Test @@ -109,7 +119,7 @@ void registerPatternWithIncludesAndExcludes() { this.resourceHints.registerPattern(resourceHint -> resourceHint.includes("com/example/*.properties").excludes("com/example/to-ignore.properties")); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies(patternOf( - List.of("com", "com/example", "com/example/*.properties"), + List.of("/", "com", "com/example", "com/example/*.properties"), List.of("com/example/to-ignore.properties"))); } @@ -118,7 +128,7 @@ void registerIfPresentRegisterExistingLocation() { this.resourceHints.registerPatternIfPresent(null, "META-INF/", resourceHint -> resourceHint.includes("com/example/*.properties")); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("com", "com/example", "com/example/*.properties")); + patternOf("/", "com", "com/example", "com/example/*.properties")); } @Test @@ -152,7 +162,7 @@ void registerResourceWithExistingClassPathResource() { ClassPathResource resource = new ClassPathResource(path); this.resourceHints.registerResource(resource); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", path)); + patternOf("/", "org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", path)); } @Test @@ -161,7 +171,7 @@ void registerResourceWithExistingRelativeClassPathResource() { ClassPathResource resource = new ClassPathResource("support", RuntimeHints.class); this.resourceHints.registerResource(resource); assertThat(this.resourceHints.resourcePatternHints()).singleElement().satisfies( - patternOf("org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", path)); + patternOf("/", "org", "org/springframework", "org/springframework/aot", "org/springframework/aot/hint", path)); } @Test @@ -197,8 +207,7 @@ private Consumer patternOf(List includes, List { assertThat(resourceHint.getIncludes()).map(ResourcePatternHint::getPattern) - .containsExactlyInAnyOrder("java", "java/lang", "java/lang/String.class"); + .containsExactlyInAnyOrder("/", "java", "java/lang", "java/lang/String.class"); assertThat(resourceHint.getExcludes()).isEmpty(); }); } diff --git a/spring-core/src/test/java/org/springframework/aot/hint/support/FilePatternResourceHintsRegistrarTests.java b/spring-core/src/test/java/org/springframework/aot/hint/support/FilePatternResourceHintsRegistrarTests.java index 3c280fb05d5a..15906820e88f 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/support/FilePatternResourceHintsRegistrarTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/support/FilePatternResourceHintsRegistrarTests.java @@ -89,7 +89,7 @@ void registerWithLocationWithoutTrailingSlash() { new FilePatternResourceHintsRegistrar(List.of("test"), List.of("META-INF"), List.of(".txt")) .registerHints(this.hints, null); assertThat(this.hints.resourcePatternHints()).singleElement() - .satisfies(includes("META-INF", "META-INF/test*.txt")); + .satisfies(includes("/", "META-INF", "META-INF/test*.txt")); } @Test @@ -105,7 +105,7 @@ void registerWithLocationUsingResourceClasspathPrefix() { new FilePatternResourceHintsRegistrar(List.of("test"), List.of("classpath:META-INF"), List.of(".txt")) .registerHints(this.hints, null); assertThat(this.hints.resourcePatternHints()).singleElement() - .satisfies(includes("META-INF", "META-INF/test*.txt")); + .satisfies(includes("/", "META-INF", "META-INF/test*.txt")); } @Test @@ -113,7 +113,7 @@ void registerWithLocationUsingResourceClasspathPrefixAndTrailingSlash() { new FilePatternResourceHintsRegistrar(List.of("test"), List.of("classpath:/META-INF"), List.of(".txt")) .registerHints(this.hints, null); assertThat(this.hints.resourcePatternHints()).singleElement() - .satisfies(includes("META-INF", "META-INF/test*.txt")); + .satisfies(includes("/", "META-INF", "META-INF/test*.txt")); } @Test diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java index f65d24e8d8b6..db6d82a421af 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java @@ -176,6 +176,7 @@ void resourceConfig() throws IOException, JSONException { "resources": { "includes": [ {"pattern": "\\\\Qcom/example/test.properties\\\\E"}, + {"pattern": "\\\\Q/\\\\E"}, {"pattern": "\\\\Qcom\\\\E"}, {"pattern": "\\\\Qcom/example\\\\E"}, {"pattern": "\\\\Qcom/example/another.properties\\\\E"} diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java index e79012235931..a07a52191f07 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java @@ -50,6 +50,7 @@ void registerExactMatch() throws JSONException { "resources": { "includes": [ { "pattern": "\\\\Qcom/example/test.properties\\\\E"}, + { "pattern": "\\\\Q/\\\\E" }, { "pattern": "\\\\Qcom\\\\E"}, { "pattern": "\\\\Qcom/example\\\\E"}, { "pattern": "\\\\Qcom/example/another.properties\\\\E"} @@ -82,6 +83,7 @@ void registerWildcardInTheMiddlePattern() throws JSONException { "resources": { "includes": [ { "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"}, + { "pattern": "\\\\Q/\\\\E" }, { "pattern": "\\\\Qcom\\\\E"}, { "pattern": "\\\\Qcom/example\\\\E"} ] @@ -98,6 +100,7 @@ void registerWildcardAtTheEndPattern() throws JSONException { "resources": { "includes": [ { "pattern": "\\\\Qstatic/\\\\E.*"}, + { "pattern": "\\\\Q/\\\\E" }, { "pattern": "\\\\Qstatic\\\\E"} ] } @@ -114,6 +117,7 @@ void registerPatternWithIncludesAndExcludes() throws JSONException { "resources": { "includes": [ { "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"}, + { "pattern": "\\\\Q/\\\\E"}, { "pattern": "\\\\Qcom\\\\E"}, { "pattern": "\\\\Qcom/example\\\\E"}, { "pattern": "\\\\Qorg/other/\\\\E.*\\\\Q.properties\\\\E"}, @@ -137,6 +141,7 @@ void registerWithReachableTypeCondition() throws JSONException { "resources": { "includes": [ { "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example/test.properties\\\\E"}, + { "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Q/\\\\E"}, { "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom\\\\E"}, { "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example\\\\E"} ] @@ -153,6 +158,7 @@ void registerType() throws JSONException { "resources": { "includes": [ { "pattern": "\\\\Qjava/lang/String.class\\\\E" }, + { "pattern": "\\\\Q/\\\\E" }, { "pattern": "\\\\Qjava\\\\E" }, { "pattern": "\\\\Qjava/lang\\\\E" } ]