Skip to content

Commit 989eb37

Browse files
committed
Update AOT resource hints with new GraalVM behavior
Prior to this commit, the resource hints for AOT applications would generate JSON metadata with `java.util.regex.Pattern`, like: ``` { "resources": { "includes": [ { "pattern": "\\Qbanner.txt\\E" } ] } } ``` This regexp feature, as well as "includes" and "excludes" are not supported anymore with the new metadata format. This commit removes the pattern format which is now replaced by a "glob" format. "globs" should only contain "*" (zero or more characters in a path segment) or "**" (zero or more path segments). Some instances of resource hint registration should be migrated as a result. For example, "/files/*.ext" matched both "/files/a.ext" and "/files/folder/b.txt" in the past. The new behavior matches only the former, unless the "/files/**/*.ext" glob pattern is used. This commit also removes the "excludes" support, which was not widely used and very often could lead to subtle behavior. Closes gh-31340
1 parent bd81abe commit 989eb37

File tree

3 files changed

+44
-76
lines changed

3 files changed

+44
-76
lines changed

spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHint.java

+16-19
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616

1717
package org.springframework.aot.hint;
1818

19-
import java.util.Arrays;
2019
import java.util.Objects;
21-
import java.util.regex.Pattern;
22-
import java.util.stream.Collectors;
2320

2421
import org.springframework.lang.Nullable;
22+
import org.springframework.util.AntPathMatcher;
2523
import org.springframework.util.Assert;
2624

2725
/**
@@ -31,16 +29,18 @@
3129
* resource on the classpath, or alternatively may contain the special
3230
* {@code *} character to indicate a wildcard match. For example:
3331
* <ul>
34-
* <li>{@code file.properties}: matches just the {@code file.properties}
32+
* <li>"file.properties": matches just the {@code file.properties}
3533
* file at the root of the classpath.</li>
36-
* <li>{@code com/example/file.properties}: matches just the
34+
* <li>"com/example/file.properties": matches just the
3735
* {@code file.properties} file in {@code com/example/}.</li>
38-
* <li>{@code *.properties}: matches all the files with a {@code .properties}
39-
* extension anywhere in the classpath.</li>
40-
* <li>{@code com/example/*.properties}: matches all the files with a {@code .properties}
41-
* extension in {@code com/example/} and its child directories at any depth.</li>
42-
* <li>{@code com/example/*}: matches all the files in {@code com/example/}
36+
* <li>"*.properties": matches all the files with a {@code .properties}
37+
* extension at the root of the classpath.</li>
38+
* <li>"com/example/*.properties": matches all the files with a {@code .properties}
39+
* extension in {@code com/example/}.</li>
40+
* <li>"com/example/{@literal **}": matches all the files in {@code com/example/}
4341
* and its child directories at any depth.</li>
42+
* <li>"com/example/{@literal **}/*.properties": matches all the files with a {@code .properties}
43+
* extension in {@code com/example/} and its child directories at any depth.</li>
4444
* </ul>
4545
*
4646
* <p>A resource pattern must not start with a slash ({@code /}) unless it is the
@@ -54,6 +54,8 @@
5454
*/
5555
public final class ResourcePatternHint implements ConditionalHint {
5656

57+
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
58+
5759
private final String pattern;
5860

5961
@Nullable
@@ -77,16 +79,11 @@ public String getPattern() {
7779
}
7880

7981
/**
80-
* Return the regex {@link Pattern} to use for identifying the resources to match.
82+
* Whether the given path matches the current glob pattern.
83+
* @param path the path to match against
8184
*/
82-
public Pattern toRegex() {
83-
String prefix = (this.pattern.startsWith("*") ? ".*" : "");
84-
String suffix = (this.pattern.endsWith("*") ? ".*" : "");
85-
String regex = Arrays.stream(this.pattern.split("\\*"))
86-
.filter(s -> !s.isEmpty())
87-
.map(Pattern::quote)
88-
.collect(Collectors.joining(".*", prefix, suffix));
89-
return Pattern.compile(regex);
85+
public boolean matches(String path) {
86+
return PATH_MATCHER.match(this.pattern, path);
9087
}
9188

9289
@Nullable

spring-core/src/main/java/org/springframework/aot/hint/ResourcePatternHints.java

+2-37
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,9 @@ public final class ResourcePatternHints {
3838

3939
private final List<ResourcePatternHint> includes;
4040

41-
private final List<ResourcePatternHint> excludes;
42-
4341

4442
private ResourcePatternHints(Builder builder) {
4543
this.includes = new ArrayList<>(builder.includes);
46-
this.excludes = new ArrayList<>(builder.excludes);
4744
}
4845

4946
/**
@@ -54,14 +51,6 @@ public List<ResourcePatternHint> getIncludes() {
5451
return this.includes;
5552
}
5653

57-
/**
58-
* Return the exclude patterns to use to identify the resources to match.
59-
* @return the exclude patterns
60-
*/
61-
public List<ResourcePatternHint> getExcludes() {
62-
return this.excludes;
63-
}
64-
6554

6655
/**
6756
* Builder for {@link ResourcePatternHints}.
@@ -70,13 +59,11 @@ public static class Builder {
7059

7160
private final Set<ResourcePatternHint> includes = new LinkedHashSet<>();
7261

73-
private final Set<ResourcePatternHint> excludes = new LinkedHashSet<>();
74-
7562
Builder() {
7663
}
7764

7865
/**
79-
* Include resources matching the specified patterns.
66+
* Include resources matching the specified glob patterns.
8067
* @param reachableType the type that should be reachable for this hint to apply
8168
* @param includes the include patterns (see {@link ResourcePatternHint} documentation)
8269
* @return {@code this}, to facilitate method chaining
@@ -129,36 +116,14 @@ private List<String> expandToIncludeDirectories(String includePattern) {
129116
}
130117

131118
/**
132-
* Include resources matching the specified patterns.
119+
* Include resources matching the specified glob patterns.
133120
* @param includes the include patterns (see {@link ResourcePatternHint} documentation)
134121
* @return {@code this}, to facilitate method chaining
135122
*/
136123
public Builder includes(String... includes) {
137124
return includes(null, includes);
138125
}
139126

140-
/**
141-
* Exclude resources matching the specified patterns.
142-
* @param reachableType the type that should be reachable for this hint to apply
143-
* @param excludes the exclude patterns (see {@link ResourcePatternHint} documentation)
144-
* @return {@code this}, to facilitate method chaining
145-
*/
146-
public Builder excludes(@Nullable TypeReference reachableType, String... excludes) {
147-
List<ResourcePatternHint> newExcludes = Arrays.stream(excludes)
148-
.map(include -> new ResourcePatternHint(include, reachableType)).toList();
149-
this.excludes.addAll(newExcludes);
150-
return this;
151-
}
152-
153-
/**
154-
* Exclude resources matching the specified patterns.
155-
* @param excludes the exclude patterns (see {@link ResourcePatternHint} documentation)
156-
* @return {@code this}, to facilitate method chaining
157-
*/
158-
public Builder excludes(String... excludes) {
159-
return excludes(null, excludes);
160-
}
161-
162127
/**
163128
* Create {@link ResourcePatternHints} based on the state of this
164129
* builder.

spring-core/src/test/java/org/springframework/aot/hint/ResourcePatternHintTests.java

+26-20
Original file line numberDiff line numberDiff line change
@@ -39,49 +39,55 @@ void patternWithLeadingSlashIsRejected() {
3939
@Test
4040
void rootDirectory() {
4141
ResourcePatternHint hint = new ResourcePatternHint("/", null);
42-
assertThat(hint.toRegex().asMatchPredicate())
43-
.accepts("/")
44-
.rejects("/com/example", "/file.txt");
42+
assertThat(hint.matches("/")).isTrue();
43+
assertThat(hint.matches("/com/example")).isFalse();
44+
assertThat(hint.matches("/file.txt")).isFalse();
4545
}
4646

4747
@Test
4848
void fileAtRoot() {
4949
ResourcePatternHint hint = new ResourcePatternHint("file.properties", null);
50-
assertThat(hint.toRegex().asMatchPredicate())
51-
.accepts("file.properties")
52-
.rejects("com/example/file.properties", "file.prop", "another-file.properties");
50+
assertThat(hint.matches("file.properties")).isTrue();
51+
assertThat(hint.matches("com/example/file.properties")).isFalse();
52+
assertThat(hint.matches("file.prop")).isFalse();
53+
assertThat(hint.matches("another-file.properties")).isFalse();
5354
}
5455

5556
@Test
5657
void fileInDirectory() {
5758
ResourcePatternHint hint = new ResourcePatternHint("com/example/file.properties", null);
58-
assertThat(hint.toRegex().asMatchPredicate())
59-
.accepts("com/example/file.properties")
60-
.rejects("file.properties", "com/file.properties", "com/example/another-file.properties");
59+
assertThat(hint.matches("com/example/file.properties")).isTrue();
60+
assertThat(hint.matches("file.properties")).isFalse();
61+
assertThat(hint.matches("com/file.properties")).isFalse();
62+
assertThat(hint.matches("com/example/another-file.properties")).isFalse();
6163
}
6264

6365
@Test
6466
void extension() {
65-
ResourcePatternHint hint = new ResourcePatternHint("*.properties", null);
66-
assertThat(hint.toRegex().asMatchPredicate())
67-
.accepts("file.properties", "com/example/file.properties")
68-
.rejects("file.prop", "com/example/file.prop");
67+
ResourcePatternHint hint = new ResourcePatternHint("**/*.properties", null);
68+
assertThat(hint.matches("file.properties")).isTrue();
69+
assertThat(hint.matches("com/example/file.properties")).isTrue();
70+
assertThat(hint.matches("file.prop")).isFalse();
71+
assertThat(hint.matches("com/example/file.prop")).isFalse();
6972
}
7073

7174
@Test
7275
void extensionInDirectoryAtAnyDepth() {
7376
ResourcePatternHint hint = new ResourcePatternHint("com/example/*.properties", null);
74-
assertThat(hint.toRegex().asMatchPredicate())
75-
.accepts("com/example/file.properties", "com/example/another/file.properties")
76-
.rejects("file.properties", "com/file.properties");
77+
assertThat(hint.matches("com/example/file.properties")).isTrue();
78+
assertThat(hint.matches("com/example/another/file.properties")).isFalse();
79+
assertThat(hint.matches("com/file.properties")).isFalse();
80+
assertThat(hint.matches("file.properties")).isFalse();
7781
}
7882

7983
@Test
8084
void anyFileInDirectoryAtAnyDepth() {
81-
ResourcePatternHint hint = new ResourcePatternHint("com/example/*", null);
82-
assertThat(hint.toRegex().asMatchPredicate())
83-
.accepts("com/example/file.properties", "com/example/another/file.properties", "com/example/another")
84-
.rejects("file.properties", "com/file.properties");
85+
ResourcePatternHint hint = new ResourcePatternHint("com/example/**", null);
86+
assertThat(hint.matches("com/example/file.properties")).isTrue();
87+
assertThat(hint.matches("com/example/another/file.properties")).isTrue();
88+
assertThat(hint.matches("com/example/another")).isTrue();
89+
assertThat(hint.matches("file.properties")).isFalse();
90+
assertThat(hint.matches("com/file.properties")).isFalse();
8591
}
8692

8793
}

0 commit comments

Comments
 (0)