diff --git a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
index f2ebf871cf..6573af5215 100644
--- a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
+++ b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
@@ -68,6 +68,7 @@ import org.springframework.lang.Nullable;
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Sam Brannen
+ * @author Vladislav Kisel
* @since 16.07.2003
*/
public class AntPathMatcher implements PathMatcher {
@@ -647,6 +648,18 @@ public class AntPathMatcher implements PathMatcher {
private final Pattern pattern;
+ private final String originalPattern;
+
+ /**
+ * True if this matcher accepts any value (e.g. regex .*)
+ */
+ private final boolean acceptAny;
+
+ /**
+ * True if given pattern is a literal pattern, thus candidate string may be tested by strings comparison for better perf.
+ */
+ private final boolean allowStringComparison;
+
private final List variableNames = new LinkedList<>();
public AntPathStringMatcher(String pattern) {
@@ -686,6 +699,10 @@ public class AntPathMatcher implements PathMatcher {
patternBuilder.append(quote(pattern, end, pattern.length()));
this.pattern = (caseSensitive ? Pattern.compile(patternBuilder.toString()) :
Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE));
+
+ this.originalPattern = pattern;
+ this.acceptAny = this.pattern.pattern().equals(DEFAULT_VARIABLE_PATTERN);
+ this.allowStringComparison = end == 0;
}
private String quote(String s, int start, int end) {
@@ -700,16 +717,22 @@ public class AntPathMatcher implements PathMatcher {
* @return {@code true} if the string matches against the pattern, or {@code false} otherwise.
*/
public boolean matchStrings(String str, @Nullable Map uriTemplateVariables) {
+ // Check whether current pattern accepts any value or given string is exact match
+ if (this.acceptAny) {
+ if (uriTemplateVariables != null) {
+ assertUrlVariablesCount(1);
+ uriTemplateVariables.put(this.variableNames.get(0), str);
+ }
+ return true;
+ }
+ else if (this.allowStringComparison && str.equals(this.originalPattern)) {
+ return true;
+ }
+
Matcher matcher = this.pattern.matcher(str);
if (matcher.matches()) {
if (uriTemplateVariables != null) {
- // SPR-8455
- if (this.variableNames.size() != matcher.groupCount()) {
- throw new IllegalArgumentException("The number of capturing groups in the pattern segment " +
- this.pattern + " does not match the number of URI template variables it defines, " +
- "which can occur if capturing groups are used in a URI template regex. " +
- "Use non-capturing groups instead.");
- }
+ assertUrlVariablesCount(matcher.groupCount());
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);
@@ -722,6 +745,17 @@ public class AntPathMatcher implements PathMatcher {
return false;
}
}
+
+ // SPR-8455
+ private void assertUrlVariablesCount(int expected) {
+ if (this.variableNames.size() != expected) {
+ throw new IllegalArgumentException("The number of capturing groups in the pattern segment " +
+ this.pattern + " does not match the number of URI template variables it defines, " +
+ "which can occur if capturing groups are used in a URI template regex. " +
+ "Use non-capturing groups instead.");
+ }
+ }
+
}
diff --git a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
index a67ebf3796..3d81cd0fa4 100644
--- a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
+++ b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
@@ -130,6 +130,9 @@ class AntPathMatcherTests {
assertThat(pathMatcher.match("", "")).isTrue();
assertThat(pathMatcher.match("/{bla}.*", "/testing.html")).isTrue();
+
+ // Test that sending the same pattern will not match (gh #24887)
+ assertThat(pathMatcher.match("/bla/{foo:[0-9]}", "/bla/{foo:[0-9]}")).isFalse();
}
@Test