From 2d29439130a9c9f5ea61986246fe007f8d9d2d78 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 22 Jun 2011 20:39:10 +0000 Subject: [PATCH] SPR-7787 Allow qualifiers in regular expressions of URI template patterns. --- .../util/AntPathStringMatcher.java | 12 ++++-- .../util/AntPathMatcherTests.java | 42 ++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/org.springframework.core/src/main/java/org/springframework/util/AntPathStringMatcher.java b/org.springframework.core/src/main/java/org/springframework/util/AntPathStringMatcher.java index 1f528ba77c..7c093a519d 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/AntPathStringMatcher.java +++ b/org.springframework.core/src/main/java/org/springframework/util/AntPathStringMatcher.java @@ -24,17 +24,18 @@ import java.util.regex.Pattern; /** * Package-protected helper class for {@link AntPathMatcher}. Tests whether or not a string matches against a pattern - * using a regular expression. + * via a {@link Pattern}. * *

The pattern may contain special characters: '*' means zero or more characters; '?' means one and only one - * character; '{' and '}' indicate a URI template pattern. + * character; '{' and '}' indicate a URI template pattern. For example /users/{user}. * * @author Arjen Poutsma + * @author Rossen Stoyanchev * @since 3.0 */ class AntPathStringMatcher { - private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{([^/]+?)\\}"); + private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}"); private static final String DEFAULT_VARIABLE_PATTERN = "(.*)"; @@ -103,6 +104,11 @@ class AntPathStringMatcher { Matcher matcher = pattern.matcher(str); if (matcher.matches()) { if (uriTemplateVariables != null) { + // SPR-8455 + Assert.isTrue(variableNames.size() == matcher.groupCount(), + "The number of capturing groups in the pattern segment " + 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."); for (int i = 1; i <= matcher.groupCount(); i++) { String name = this.variableNames.get(i - 1); String value = matcher.group(i); diff --git a/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java index 4e44905468..9133c181c2 100644 --- a/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java +++ b/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java @@ -32,6 +32,7 @@ import org.junit.Test; * @author Seth Ladd * @author Juergen Hoeller * @author Arjen Poutsma + * @author Rossen Stoyanchev */ public class AntPathMatcherTests { @@ -335,7 +336,7 @@ public class AntPathMatcherTests { } @Test - public void extractUriTemplateVariablesCustomRegex() { + public void extractUriTemplateVariablesRegex() { Map result = pathMatcher .extractUriTemplateVariables("{symbolicName:[\\w\\.]+}-{version:[\\w\\.]+}.jar", "com.example-1.0.0.jar"); @@ -347,7 +348,46 @@ public class AntPathMatcherTests { assertEquals("com.example", result.get("symbolicName")); assertEquals("1.0.0", result.get("version")); } + + // SPR-7787 + + @Test + public void extractUriTemplateVarsRegexQualifiers() { + Map result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar", + "com.example-sources-1.0.0.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + + result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\w\\.]+}-sources-{version:[\\d\\.]+}-{year:\\d{4}}{month:\\d{2}}{day:\\d{2}}.jar", + "com.example-sources-1.0.0-20100220.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + assertEquals("2010", result.get("year")); + assertEquals("02", result.get("month")); + assertEquals("20", result.get("day")); + + result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.\\{\\}]+}.jar", + "com.example-sources-1.0.0.{12}.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0.{12}", result.get("version")); + } + // SPR-8455 + + @Test + public void extractUriTemplateVarsRegexCapturingGroups() { + try { + pathMatcher.extractUriTemplateVariables("/web/{id:foo(bar)?}", "/web/foobar"); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertTrue("Expected helpful message on the use of capturing groups", + e.getMessage().contains("The number of capturing groups in the pattern")); + } + } + @Test public void combine() { assertEquals("", pathMatcher.combine(null, null));