diff --git a/spring-web/src/main/java/org/springframework/web/util/ParsingPathMatcher.java b/spring-web/src/main/java/org/springframework/web/util/ParsingPathMatcher.java
index fff0d2af73..5f7aa0379b 100644
--- a/spring-web/src/main/java/org/springframework/web/util/ParsingPathMatcher.java
+++ b/spring-web/src/main/java/org/springframework/web/util/ParsingPathMatcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util;
import java.util.Comparator;
@@ -26,16 +27,22 @@ import org.springframework.web.util.patterns.PatternComparatorConsideringPath;
/**
- *
+ * {@link PathMatcher} implementation for path patterns parsed
+ * as {@link PathPatternParser} and compiled as {@link PathPattern}s.
+ *
+ *
Once parsed, {@link PathPattern}s are tailored for fast matching
+ * and quick comparison.
+ *
* @author Andy Clement
* @since 5.0
+ * @see PathPattern
*/
public class ParsingPathMatcher implements PathMatcher {
- Map cache = new HashMap<>();
-
+ Map cache = new HashMap<>();
+
PathPatternParser parser;
-
+
public ParsingPathMatcher() {
parser = new PathPatternParser();
}
@@ -74,27 +81,28 @@ public class ParsingPathMatcher implements PathMatcher {
public Comparator getPatternComparator(String path) {
return new PathPatternStringComparatorConsideringPath(path);
}
-
+
class PathPatternStringComparatorConsideringPath implements Comparator {
-
+
PatternComparatorConsideringPath ppcp;
-
+
public PathPatternStringComparatorConsideringPath(String path) {
ppcp = new PatternComparatorConsideringPath(path);
}
-
+
@Override
public int compare(String o1, String o2) {
if (o1 == null) {
- return (o2==null?0:+1);
- } else if (o2 == null) {
+ return (o2 == null ? 0 : +1);
+ }
+ else if (o2 == null) {
return -1;
}
PathPattern p1 = getPathPattern(o1);
PathPattern p2 = getPathPattern(o2);
- return ppcp.compare(p1,p2);
+ return ppcp.compare(p1, p2);
}
-
+
}
@Override
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/CaptureTheRestPathElement.java b/spring-web/src/main/java/org/springframework/web/util/patterns/CaptureTheRestPathElement.java
index 659b28e74f..9e4fad18a3 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/CaptureTheRestPathElement.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/CaptureTheRestPathElement.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import org.springframework.web.util.patterns.PathPattern.MatchingContext;
@@ -20,13 +21,13 @@ import org.springframework.web.util.patterns.PathPattern.MatchingContext;
/**
* A path element representing capturing the rest of a path. In the pattern
* '/foo/{*foobar}' the /{*foobar} is represented as a {@link CaptureTheRestPathElement}.
- *
+ *
* @author Andy Clement
*/
class CaptureTheRestPathElement extends PathElement {
private String variableName;
-
+
private char separator;
/**
@@ -45,14 +46,14 @@ class CaptureTheRestPathElement extends PathElement {
// No need to handle 'match start' checking as this captures everything
// anyway and cannot be followed by anything else
// assert next == null
-
+
// If there is more data, it must start with the separator
- if (candidateIndexPathPatterns match URL paths using the following rules:
+ *
+ * - {@code ?} matches one character
+ * - {@code *} matches zero or more characters within a path segment
+ * - {@code **} matches zero or more path segments until the end of the path
+ * - {@code {spring}} matches a path segment and captures it as a variable named "spring"
+ * - {@code {spring:[a-z]+}} matches the regexp {@code [a-z]+} as a path variable named "spring"
+ * - {@code {*spring}} matches zero or more path segments until the end of the path
+ * and captures it as a variable named "spring"
+ *
+ *
+ * Examples
+ *
+ * - {@code /pages/t?st.html} — matches {@code /pages/test.html} but also
+ * {@code /pages/tast.html} but not {@code /pages/toast.html}
+ * - {@code /resources/*.png} — matches all {@code .png} files in the
+ * {@code resources} directory
+ * /resources/**
— matches all files
+ * underneath the {@code /resources/} path, including {@code /resources/image.png}
+ * and {@code /resources/css/spring.css}
+ * /resources/{*path}
— matches all files
+ * underneath the {@code /resources/} path and captures their relative path in
+ * a variable named "path"; {@code /resources/image.png} will match with
+ * "spring" -> "/image.png", and {@code /resources/css/spring.css} will match
+ * with "spring" -> "/css/spring.css"
+ * - {@code /resources/{filename:\\w+}.dat} will match {@code /resources/spring.dat}
+ * and assign the value {@code "spring"} to the {@code filename} variable
+ *
+ *
* @author Andy Clement
+ * @since 5.0
*/
public class PathPattern implements Comparable {
- private final static Map NO_VARIABLES_MAP = Collections.emptyMap();
+ private final static Map NO_VARIABLES_MAP = Collections.emptyMap();
/** First path element in the parsed chain of path elements for this pattern */
private PathElement head;
/** The text of the parsed pattern */
private String patternString;
-
+
/** The separator used when parsing the pattern */
private char separator;
@@ -54,7 +85,7 @@ public class PathPattern implements Comparable {
* Useful when comparing two patterns.
*/
int normalizedLength;
-
+
/**
* Does the pattern end with '<separator>*'
*/
@@ -87,8 +118,9 @@ public class PathPattern implements Comparable {
if (s instanceof CaptureTheRestPathElement || s instanceof WildcardTheRestPathElement) {
this.isCatchAll = true;
}
- if (s instanceof SeparatorPathElement && s.next!=null && s.next instanceof WildcardPathElement && s.next.next == null) {
- this.endsWithSeparatorWildcard=true;
+ if (s instanceof SeparatorPathElement && s.next != null
+ && s.next instanceof WildcardPathElement && s.next.next == null) {
+ this.endsWithSeparatorWildcard = true;
}
s = s.next;
}
@@ -101,28 +133,31 @@ public class PathPattern implements Comparable {
public boolean matches(String path) {
if (head == null) {
return (path == null) || (path.length() == 0);
- } else if (path == null || path.length() == 0) {
+ }
+ else if (path == null || path.length() == 0) {
if (head instanceof WildcardTheRestPathElement || head instanceof CaptureTheRestPathElement) {
path = ""; // Will allow CaptureTheRest to bind the variable to empty
- } else {
+ }
+ else {
return false;
}
}
- MatchingContext matchingContext = new MatchingContext(path,false);
+ MatchingContext matchingContext = new MatchingContext(path, false);
return head.matches(0, matchingContext);
}
-
+
/**
* @param path the path to check against the pattern
* @return true if the pattern matches as much of the path as is supplied
*/
public boolean matchStart(String path) {
if (head == null) {
- return (path==null || path.length() == 0);
- } else if (path == null || path.length() == 0) {
+ return (path == null || path.length() == 0);
+ }
+ else if (path == null || path.length() == 0) {
return true;
}
- MatchingContext matchingContext = new MatchingContext(path,false);
+ MatchingContext matchingContext = new MatchingContext(path, false);
matchingContext.setMatchStartMatching(true);
return head.matches(0, matchingContext);
}
@@ -132,14 +167,17 @@ public class PathPattern implements Comparable {
* @return a map of extracted variables - an empty map if no variables extracted.
*/
public Map matchAndExtract(String path) {
- MatchingContext matchingContext = new MatchingContext(path,true);
+ MatchingContext matchingContext = new MatchingContext(path, true);
if (head != null && head.matches(0, matchingContext)) {
return matchingContext.getExtractedVariables();
- } else {
- if (path== null || path.length()==0) {
+ }
+ else {
+ if (path == null || path.length() == 0) {
return NO_VARIABLES_MAP;
- } else {
- throw new IllegalStateException("Pattern \"" + this.toString() + "\" is not a match for \"" + path + "\"");
+ }
+ else {
+ throw new IllegalStateException("Pattern \"" + this.toString()
+ + "\" is not a match for \"" + path + "\"");
}
}
}
@@ -150,7 +188,7 @@ public class PathPattern implements Comparable {
public String getPatternString() {
return patternString;
}
-
+
public PathElement getHeadSection() {
return head;
}
@@ -168,17 +206,18 @@ public class PathPattern implements Comparable {
* the returned path.
* @param path a path that matches this pattern
* @return the subset of the path that is matched by pattern or "" if none of it is matched by pattern elements
- */
+ */
public String extractPathWithinPattern(String path) {
// assert this.matches(path)
PathElement s = head;
int separatorCount = 0;
// Find first path element that is pattern based
while (s != null) {
- if (s instanceof SeparatorPathElement || s instanceof CaptureTheRestPathElement || s instanceof WildcardTheRestPathElement) {
+ if (s instanceof SeparatorPathElement || s instanceof CaptureTheRestPathElement
+ || s instanceof WildcardTheRestPathElement) {
separatorCount++;
}
- if (s.getWildcardCount()!=0 || s.getCaptureCount()!=0) {
+ if (s.getWildcardCount() != 0 || s.getCaptureCount() != 0) {
break;
}
s = s.next;
@@ -201,7 +240,7 @@ public class PathPattern implements Comparable {
}
int end = len;
// Trim trailing separators
- while (path.charAt(end-1) == separator) {
+ while (path.charAt(end - 1) == separator) {
end--;
}
// Check if multiple separators embedded in the resulting path, if so trim them out.
@@ -209,19 +248,19 @@ public class PathPattern implements Comparable {
// The stringWithDuplicateSeparatorsRemoved is only computed if necessary
int c = pos;
StringBuilder stringWithDuplicateSeparatorsRemoved = null;
- while (c {
if (stringWithDuplicateSeparatorsRemoved != null) {
return stringWithDuplicateSeparatorsRemoved.toString();
}
- return pos == len ? "" : path.substring(pos,end);
+ return pos == len ? "" : path.substring(pos, end);
}
-
+
/**
* Compare this pattern with a supplied pattern. Return -1,0,+1 if this pattern
* is more specific, the same or less specific than the supplied pattern.
@@ -254,10 +293,12 @@ public class PathPattern implements Comparable {
if (lenDifference != 0) {
return (lenDifference < 0) ? +1 : -1;
}
- } else {
+ }
+ else {
return +1;
}
- } else if (p.isCatchAll()) {
+ }
+ else if (p.isCatchAll()) {
return -1;
}
// 3) This will sort such that if they differ in terms of wildcards or
@@ -306,7 +347,7 @@ public class PathPattern implements Comparable {
public String toChainString() {
StringBuilder buf = new StringBuilder();
PathElement pe = head;
- while (pe!=null) {
+ while (pe != null) {
buf.append(pe.toString()).append(" ");
pe = pe.next;
}
@@ -320,7 +361,7 @@ public class PathPattern implements Comparable {
public int getCapturedVariableCount() {
return capturedVariableCount;
}
-
+
public String toString() {
return patternString;
}
@@ -340,7 +381,7 @@ public class PathPattern implements Comparable {
boolean isMatchStartMatching = false;
- private Map extractedVariables;
+ private Map extractedVariables;
public boolean extractingVariables;
@@ -361,10 +402,11 @@ public class PathPattern implements Comparable {
extractedVariables.put(key, value);
}
- public Map getExtractedVariables() {
+ public Map getExtractedVariables() {
if (this.extractedVariables == null) {
return NO_VARIABLES_MAP;
- } else {
+ }
+ else {
return this.extractedVariables;
}
}
@@ -372,7 +414,7 @@ public class PathPattern implements Comparable {
/**
* Scan ahead from the specified position for either the next separator
* character or the end of the candidate.
- *
+ *
* @param pos the starting position for the scan
* @return the position of the next separator or the end of the candidate
*/
@@ -392,62 +434,65 @@ public class PathPattern implements Comparable {
*/
public String combine(String pattern2string) {
// If one of them is empty the result is the other. If both empty the result is ""
- if (patternString == null || patternString.length()==0) {
- if (pattern2string == null || pattern2string.length()==0) {
+ if (patternString == null || patternString.length() == 0) {
+ if (pattern2string == null || pattern2string.length() == 0) {
return "";
- } else {
+ }
+ else {
return pattern2string;
}
- } else if (pattern2string == null || pattern2string.length()==0) {
+ }
+ else if (pattern2string == null || pattern2string.length() == 0) {
return patternString;
}
-
+
// /* + /hotel => /hotel
// /*.* + /*.html => /*.html
// However:
// /usr + /user => /usr/user
// /{foo} + /bar => /{foo}/bar
- if (!patternString.equals(pattern2string) && capturedVariableCount==0 && matches(pattern2string)) {
+ if (!patternString.equals(pattern2string) && capturedVariableCount == 0 && matches(pattern2string)) {
return pattern2string;
}
// /hotels/* + /booking => /hotels/booking
// /hotels/* + booking => /hotels/booking
if (endsWithSeparatorWildcard) {
- return concat(patternString.substring(0,patternString.length()-2), pattern2string);
+ return concat(patternString.substring(0, patternString.length() - 2), pattern2string);
}
// /hotels + /booking => /hotels/booking
// /hotels + booking => /hotels/booking
int starDotPos1 = patternString.indexOf("*."); // Are there any file prefix/suffix things to consider?
- if (capturedVariableCount!=0 || starDotPos1 == -1 || separator=='.') {
- return concat(patternString, pattern2string);
+ if (capturedVariableCount != 0 || starDotPos1 == -1 || separator == '.') {
+ return concat(patternString, pattern2string);
}
-
+
// /*.html + /hotel => /hotel.html
// /*.html + /hotel.* => /hotel.html
- String firstExtension = patternString.substring(starDotPos1+1); // looking for the first extension
+ String firstExtension = patternString.substring(starDotPos1 + 1); // looking for the first extension
int dotPos2 = pattern2string.indexOf('.');
- String file2 = (dotPos2==-1?pattern2string:pattern2string.substring(0,dotPos2));
- String secondExtension = (dotPos2 == -1?"":pattern2string.substring(dotPos2));
+ String file2 = (dotPos2 == -1 ? pattern2string : pattern2string.substring(0, dotPos2));
+ String secondExtension = (dotPos2 == -1 ? "" : pattern2string.substring(dotPos2));
boolean firstExtensionWild = (firstExtension.equals(".*") || firstExtension.equals(""));
boolean secondExtensionWild = (secondExtension.equals(".*") || secondExtension.equals(""));
if (!firstExtensionWild && !secondExtensionWild) {
throw new IllegalArgumentException("Cannot combine patterns: " + patternString + " and " + pattern2string);
}
- return file2 + (firstExtensionWild?secondExtension:firstExtension);
+ return file2 + (firstExtensionWild ? secondExtension : firstExtension);
}
/**
- * Join two paths together including a separator if necessary. Extraneous separators are removed (if the first path
+ * Join two paths together including a separator if necessary.
+ * Extraneous separators are removed (if the first path
* ends with one and the second path starts with one).
* @param path1 First path
* @param path2 Second path
* @return joined path that may include separator if necessary
*/
private String concat(String path1, String path2) {
- boolean path1EndsWithSeparator = path1.charAt(path1.length()-1)==separator;
- boolean path2StartsWithSeparator = path2.charAt(0)==separator;
+ boolean path1EndsWithSeparator = path1.charAt(path1.length() - 1) == separator;
+ boolean path2StartsWithSeparator = path2.charAt(0) == separator;
if (path1EndsWithSeparator && path2StartsWithSeparator) {
return path1 + path2.substring(1);
}
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternComparator.java b/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternComparator.java
index 167774dba1..9470fc1d7d 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternComparator.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternComparator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.util.Comparator;
/**
* Basic PathPattern comparator.
- *
+ *
* @author Andy Clement
*/
public class PathPatternComparator implements Comparator {
@@ -28,8 +29,9 @@ public class PathPatternComparator implements Comparator {
public int compare(PathPattern o1, PathPattern o2) {
// Nulls get sorted to the end
if (o1 == null) {
- return (o2==null?0:+1);
- } else if (o2 == null) {
+ return (o2 == null ? 0 : +1);
+ }
+ else if (o2 == null) {
return -1;
}
return o1.compareTo(o2);
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternParser.java b/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternParser.java
index 31317e267a..fbdd5b9eaf 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternParser.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/PathPatternParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.util.ArrayList;
@@ -21,9 +22,10 @@ import java.util.regex.PatternSyntaxException;
/**
* Parser for URI template patterns. It breaks the path pattern into a number of
- * path elements in a linked list.
- *
+ * {@link PathElement}s in a linked list.
+ *
* @author Andy Clement
+ * @since 5.0
*/
public class PathPatternParser {
@@ -85,7 +87,7 @@ public class PathPatternParser {
/**
* Create a PatternParser that will use the specified separator instead of
* the default.
- *
+ *
* @param separator the path separator to look for when parsing.
*/
public PathPatternParser(char separator) {
@@ -101,7 +103,7 @@ public class PathPatternParser {
* path elements around separator boundaries and verifying the structure at each
* stage. Produces a PathPattern object that can be used for fast matching
* against paths.
- *
+ *
* @param pathPattern the input path pattern, e.g. /foo/{bar}
* @return a PathPattern for quickly matching paths against the specified path pattern
*/
@@ -128,32 +130,37 @@ public class PathPatternParser {
pushPathElement(createPathElement());
}
// Skip over multiple separators
- while ((pos+1) < pathPatternLength && pathPatternData[pos+1] == separator) {
+ while ((pos + 1) < pathPatternLength && pathPatternData[pos + 1] == separator) {
pos++;
}
if (peekDoubleWildcard()) {
- pushPathElement(new WildcardTheRestPathElement(pos,separator));
- pos+=2;
- } else {
+ pushPathElement(new WildcardTheRestPathElement(pos, separator));
+ pos += 2;
+ }
+ else {
pushPathElement(new SeparatorPathElement(pos, separator));
}
- } else {
+ }
+ else {
if (pathElementStart == -1) {
pathElementStart = pos;
}
if (ch == '?') {
singleCharWildcardCount++;
- } else if (ch == '{') {
+ }
+ else if (ch == '{') {
if (insideVariableCapture) {
throw new PatternParseException(pos, pathPatternData, PatternMessage.ILLEGAL_NESTED_CAPTURE);
- // If we enforced that adjacent captures weren't allowed, this would do it (this would be an error: /foo/{bar}{boo}/)
+ // If we enforced that adjacent captures weren't allowed,
+ // // this would do it (this would be an error: /foo/{bar}{boo}/)
// } else if (pos > 0 && pathPatternData[pos - 1] == '}') {
// throw new PatternParseException(pos, pathPatternData,
// PatternMessage.CANNOT_HAVE_ADJACENT_CAPTURES);
}
insideVariableCapture = true;
variableCaptureStart = pos;
- } else if (ch == '}') {
+ }
+ else if (ch == '}') {
if (!insideVariableCapture) {
throw new PatternParseException(pos, pathPatternData, PatternMessage.MISSING_OPEN_CAPTURE);
}
@@ -163,13 +170,15 @@ public class PathPatternParser {
PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
}
variableCaptureCount++;
- } else if (ch == ':') {
+ }
+ else if (ch == ':') {
if (insideVariableCapture) {
skipCaptureRegex();
insideVariableCapture = false;
variableCaptureCount++;
}
- } else if (ch == '*') {
+ }
+ else if (ch == '*') {
if (insideVariableCapture) {
if (variableCaptureStart == pos - 1) {
isCaptureTheRestVariable = true;
@@ -185,7 +194,8 @@ public class PathPatternParser {
PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR,
Character.toString(ch));
- } else if ((pos > (variableCaptureStart + 1 + (isCaptureTheRestVariable ? 1 : 0))
+ }
+ else if ((pos > (variableCaptureStart + 1 + (isCaptureTheRestVariable ? 1 : 0))
&& !Character.isJavaIdentifierPart(ch))) {
throw new PatternParseException(pos, pathPatternData,
PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR, Character.toString(ch));
@@ -219,10 +229,11 @@ public class PathPatternParser {
pos++;
previousBackslash = true;
continue;
- }
+ }
if (ch == '{' && !previousBackslash) {
curlyBracketDepth++;
- } else if (ch == '}' && !previousBackslash) {
+ }
+ else if (ch == '}' && !previousBackslash) {
if (curlyBracketDepth == 0) {
if (regexStart == pos) {
throw new PatternParseException(regexStart, pathPatternData,
@@ -236,7 +247,7 @@ public class PathPatternParser {
throw new PatternParseException(pos, pathPatternData, PatternMessage.MISSING_CLOSE_CAPTURE);
}
pos++;
- previousBackslash=false;
+ previousBackslash = false;
}
throw new PatternParseException(pos - 1, pathPatternData, PatternMessage.MISSING_CLOSE_CAPTURE);
}
@@ -265,25 +276,30 @@ public class PathPatternParser {
if (currentPE == null) {
headPE = newPathElement;
currentPE = newPathElement;
- } else if (currentPE instanceof SeparatorPathElement) {
+ }
+ else if (currentPE instanceof SeparatorPathElement) {
PathElement peBeforeSeparator = currentPE.prev;
if (peBeforeSeparator == null) {
// /{*foobar} is at the start
headPE = newPathElement;
newPathElement.prev = peBeforeSeparator;
- } else {
+ }
+ else {
peBeforeSeparator.next = newPathElement;
newPathElement.prev = peBeforeSeparator;
}
currentPE = newPathElement;
- } else {
- throw new IllegalStateException("Expected SeparatorPathElement but was "+currentPE);
}
- } else {
+ else {
+ throw new IllegalStateException("Expected SeparatorPathElement but was " + currentPE);
+ }
+ }
+ else {
if (headPE == null) {
headPE = newPathElement;
currentPE = newPathElement;
- } else {
+ }
+ else {
currentPE.next = newPathElement;
newPathElement.prev = currentPE;
currentPE = newPathElement;
@@ -305,39 +321,51 @@ public class PathPatternParser {
System.arraycopy(pathPatternData, pathElementStart, pathElementText, 0, pos - pathElementStart);
PathElement newPE = null;
if (variableCaptureCount > 0) {
- if (variableCaptureCount == 1 && pathElementStart == variableCaptureStart && pathPatternData[pos - 1] == '}') {
+ if (variableCaptureCount == 1
+ && pathElementStart == variableCaptureStart && pathPatternData[pos - 1] == '}') {
if (isCaptureTheRestVariable) {
// It is {*....}
newPE = new CaptureTheRestPathElement(pathElementStart, pathElementText, separator);
- } else {
+ }
+ else {
// It is a full capture of this element (possibly with constraint), for example: /foo/{abc}/
try {
newPE = new CaptureVariablePathElement(pathElementStart, pathElementText, caseSensitive);
- } catch (PatternSyntaxException pse) {
- throw new PatternParseException(pse, findRegexStart(pathPatternData,pathElementStart)+pse.getIndex(), pathPatternData, PatternMessage.JDK_PATTERN_SYNTAX_EXCEPTION);
+ }
+ catch (PatternSyntaxException pse) {
+ throw new PatternParseException(pse, findRegexStart(pathPatternData, pathElementStart)
+ + pse.getIndex(), pathPatternData, PatternMessage.JDK_PATTERN_SYNTAX_EXCEPTION);
}
recordCapturedVariable(pathElementStart, ((CaptureVariablePathElement) newPE).getVariableName());
}
- } else {
+ }
+ else {
if (isCaptureTheRestVariable) {
- throw new PatternParseException(pathElementStart, pathPatternData, PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
+ throw new PatternParseException(pathElementStart, pathPatternData,
+ PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
}
- RegexPathElement newRegexSection = new RegexPathElement(pathElementStart, pathElementText, caseSensitive, pathPatternData);
+ RegexPathElement newRegexSection = new RegexPathElement(pathElementStart, pathElementText,
+ caseSensitive, pathPatternData);
for (String variableName : newRegexSection.getVariableNames()) {
recordCapturedVariable(pathElementStart, variableName);
}
newPE = newRegexSection;
}
- } else {
+ }
+ else {
if (wildcard) {
if (pos - 1 == pathElementStart) {
newPE = new WildcardPathElement(pathElementStart);
- } else {
+ }
+ else {
newPE = new RegexPathElement(pathElementStart, pathElementText, caseSensitive, pathPatternData);
}
- } else if (singleCharWildcardCount!=0) {
- newPE = new SingleCharWildcardedPathElement(pathElementStart, pathElementText, singleCharWildcardCount, caseSensitive);
- } else {
+ }
+ else if (singleCharWildcardCount != 0) {
+ newPE = new SingleCharWildcardedPathElement(pathElementStart, pathElementText,
+ singleCharWildcardCount, caseSensitive);
+ }
+ else {
newPE = new LiteralPathElement(pathElementStart, pathElementText, caseSensitive);
}
}
@@ -349,11 +377,12 @@ public class PathPatternParser {
* Assumes there is a constraint pattern.
* @param data a complete path expression, e.g. /aaa/bbb/{ccc:...}
* @param offset the start of the capture pattern of interest
- * @return the index of the character after the ':' within the pattern expression relative to the start of the whole expression
+ * @return the index of the character after the ':' within
+ * the pattern expression relative to the start of the whole expression
*/
private int findRegexStart(char[] data, int offset) {
int pos = offset;
- while (pos();
}
if (capturedVariableNames.contains(variableName)) {
- throw new PatternParseException(pos, this.pathPatternData, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, variableName);
+ throw new PatternParseException(pos, this.pathPatternData,
+ PatternMessage.ILLEGAL_DOUBLE_CAPTURE, variableName);
}
capturedVariableNames.add(variableName);
}
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternComparatorConsideringPath.java b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternComparatorConsideringPath.java
index 06fb69251c..77be7bb055 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternComparatorConsideringPath.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternComparatorConsideringPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.util.Comparator;
@@ -20,13 +21,14 @@ import java.util.Comparator;
/**
* Similar to {@link PathPatternComparator} but this takes account of a specified path and
* sorts anything that exactly matches it to be first.
- *
+ *
* @author Andy Clement
+ * @since 5.0
*/
public class PatternComparatorConsideringPath implements Comparator {
private String path;
-
+
public PatternComparatorConsideringPath(String path) {
this.path = path;
}
@@ -35,13 +37,15 @@ public class PatternComparatorConsideringPath implements Comparator
public int compare(PathPattern o1, PathPattern o2) {
// Nulls get sorted to the end
if (o1 == null) {
- return (o2==null?0:+1);
- } else if (o2 == null) {
+ return (o2 == null ? 0 : +1);
+ }
+ else if (o2 == null) {
return -1;
}
if (o1.getPatternString().equals(path)) {
- return (o2.getPatternString().equals(path))?0:-1;
- } else if (o2.getPatternString().equals(path)) {
+ return (o2.getPatternString().equals(path)) ? 0 : -1;
+ }
+ else if (o2.getPatternString().equals(path)) {
return +1;
}
return o1.compareTo(o2);
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternMessage.java b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternMessage.java
index a3b8836533..0cb53f80d5 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternMessage.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternMessage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.text.MessageFormat;
/**
* The messages that can be included in a {@link PatternParseException} when there is a parse failure.
- *
+ *
* @author Andy Clement
+ * @since 5.0
*/
public enum PatternMessage {
-
+
// @formatter:off
MISSING_CLOSE_CAPTURE("Expected close capture character after variable name '}'"),
- MISSING_OPEN_CAPTURE("Missing preceeding open capture character before variable name'{'"),
+ MISSING_OPEN_CAPTURE("Missing preceeding open capture character before variable name'{'"),
ILLEGAL_NESTED_CAPTURE("Not allowed to nest variable captures"),
CANNOT_HAVE_ADJACENT_CAPTURES("Adjacent captures are not allowed"),
ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR("Character ''{0}'' is not allowed at start of captured variable name"),
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternParseException.java b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternParseException.java
index 7e40476c04..dc8ba52523 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/PatternParseException.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/PatternParseException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
/**
* Exception that is thrown when there is a problem with the pattern being parsed.
- *
+ *
* @author Andy Clement
+ * @since 5.0
*/
public class PatternParseException extends RuntimeException {
@@ -41,7 +43,7 @@ public class PatternParseException extends RuntimeException {
}
public PatternParseException(Throwable cause, int pos, char[] patternText, PatternMessage message, Object... inserts) {
- super(message.formatMessage(inserts),cause);
+ super(message.formatMessage(inserts), cause);
this.pos = pos;
this.patternText = patternText;
this.message = message;
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java b/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java
index a164718905..fe6a8a6424 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.util.LinkedList;
@@ -26,8 +27,9 @@ import org.springframework.web.util.patterns.PathPattern.MatchingContext;
* A regex path element. Used to represent any complicated element of the path.
* For example in '/foo/*_*/*_{foobar}' both *_* and *_{foobar}
* are {@link RegexPathElement} path elements. Derived from the general {@link AntPathMatcher} approach.
- *
+ *
* @author Andy Clement
+ * @since 5.0
*/
class RegexPathElement extends PathElement {
@@ -63,10 +65,12 @@ class RegexPathElement extends PathElement {
String match = matcher.group();
if ("?".equals(match)) {
patternBuilder.append('.');
- } else if ("*".equals(match)) {
+ }
+ else if ("*".equals(match)) {
patternBuilder.append(".*");
wildcardCount++;
- } else if (match.startsWith("{") && match.endsWith("}")) {
+ }
+ else if (match.startsWith("{") && match.endsWith("}")) {
int colonIdx = match.indexOf(':');
if (colonIdx == -1) {
patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
@@ -76,7 +80,8 @@ class RegexPathElement extends PathElement {
variableName);
}
this.variableNames.add(variableName);
- } else {
+ }
+ else {
String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
patternBuilder.append('(');
patternBuilder.append(variablePattern);
@@ -94,7 +99,8 @@ class RegexPathElement extends PathElement {
patternBuilder.append(quote(text, end, text.length()));
if (caseSensitive) {
pattern = java.util.regex.Pattern.compile(patternBuilder.toString());
- } else {
+ }
+ else {
pattern = java.util.regex.Pattern.compile(patternBuilder.toString(),
java.util.regex.Pattern.CASE_INSENSITIVE);
}
@@ -120,7 +126,8 @@ class RegexPathElement extends PathElement {
if (next == null) {
// No more pattern, is there more data?
matches = (p == matchingContext.candidateLength);
- } else {
+ }
+ else {
if (matchingContext.isMatchStartMatching && p == matchingContext.candidateLength) {
return true; // no more data but matches up to this point
}
@@ -165,10 +172,10 @@ class RegexPathElement extends PathElement {
public int getWildcardCount() {
return wildcardCount;
}
-
+
@Override
public int getScore() {
- return getCaptureCount()*CAPTURE_VARIABLE_WEIGHT + getWildcardCount()*WILDCARD_WEIGHT;
+ return getCaptureCount() * CAPTURE_VARIABLE_WEIGHT + getWildcardCount() * WILDCARD_WEIGHT;
}
}
\ No newline at end of file
diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/SeparatorPathElement.java b/spring-web/src/main/java/org/springframework/web/util/patterns/SeparatorPathElement.java
index d85a1cbb4e..25aaea68b1 100644
--- a/spring-web/src/main/java/org/springframework/web/util/patterns/SeparatorPathElement.java
+++ b/spring-web/src/main/java/org/springframework/web/util/patterns/SeparatorPathElement.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import org.springframework.web.util.patterns.PathPattern.MatchingContext;
@@ -21,8 +22,9 @@ import org.springframework.web.util.patterns.PathPattern.MatchingContext;
* A separator path element. In the pattern '/foo/bar' the two occurrences
* of '/' will be represented by a SeparatorPathElement (if the default
* separator of '/' is being used).
- *
+ *
* @author Andy Clement
+ * @since 5.0
*/
class SeparatorPathElement extends PathElement {
@@ -44,13 +46,14 @@ class SeparatorPathElement extends PathElement {
if (matchingContext.candidate[candidateIndex] == separator) {
// Skip further separators in the path (they are all 'matched'
// by a single SeparatorPathElement)
- while ((candidateIndex+1) extracted = checkCapture("/abc","/abc");
- assertEquals(0,extracted.size());
+ Map extracted = checkCapture("/abc", "/abc");
+ assertEquals(0, extracted.size());
}
@Test
@@ -565,7 +568,7 @@ public class PathPatternMatcherTests {
assertEquals("2010", result.get("year"));
assertEquals("02", result.get("month"));
assertEquals("20", result.get("day"));
-
+
p = pp.parse("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.\\{\\}]+}.jar");
result = p.matchAndExtract("com.example-sources-1.0.0.{12}.jar");
assertEquals("com.example", result.get("symbolicName"));
@@ -580,7 +583,7 @@ public class PathPatternMatcherTests {
exception.expectMessage(containsString("The number of capturing groups in the pattern"));
pathMatcher.matchAndExtract("/web/foobar_goo");
}
-
+
@Rule
public final ExpectedException exception = ExpectedException.none();
@@ -619,14 +622,14 @@ public class PathPatternMatcherTests {
// SPR-10554
assertEquals("/hotel", pathMatcher.combine("/", "/hotel")); // SPR-12975
assertEquals("/hotel/booking", pathMatcher.combine("/hotel/", "/booking")); // SPR-12975
- assertEquals("",pathMatcher.combine(null, null));
- assertEquals("",pathMatcher.combine(null, ""));
- assertEquals("",pathMatcher.combine("",null));
- assertEquals("",pathMatcher.combine(null, null));
- assertEquals("",pathMatcher.combine("", ""));
- assertEquals("/hotel",pathMatcher.combine("", "/hotel"));
- assertEquals("/hotel",pathMatcher.combine("/hotel", null));
- assertEquals("/hotel",pathMatcher.combine("/hotel", ""));
+ assertEquals("", pathMatcher.combine(null, null));
+ assertEquals("", pathMatcher.combine(null, ""));
+ assertEquals("", pathMatcher.combine("", null));
+ assertEquals("", pathMatcher.combine(null, null));
+ assertEquals("", pathMatcher.combine("", ""));
+ assertEquals("/hotel", pathMatcher.combine("", "/hotel"));
+ assertEquals("/hotel", pathMatcher.combine("/hotel", null));
+ assertEquals("/hotel", pathMatcher.combine("/hotel", ""));
// TODO Do we need special handling when patterns contain multiple dots?
}
@@ -703,21 +706,21 @@ public class PathPatternMatcherTests {
assertEquals(-1, comparator.compare(parse("*"), parse("*/**")));
assertEquals(1, comparator.compare(parse("*/**"), parse("*")));
}
-
+
@Test
public void pathPatternComparator() {
PathPatternComparator ppc = new PathPatternComparator();
- assertEquals(0,ppc.compare(null, null));
- assertEquals(1,ppc.compare(null, parse("")));
- assertEquals(-1,ppc.compare(parse(""), null));
- assertEquals(0,ppc.compare(parse(""), parse("")));
+ assertEquals(0, ppc.compare(null, null));
+ assertEquals(1, ppc.compare(null, parse("")));
+ assertEquals(-1, ppc.compare(parse(""), null));
+ assertEquals(0, ppc.compare(parse(""), parse("")));
}
-
+
@Test
public void patternCompareTo() {
PathPatternParser p = new PathPatternParser();
PathPattern pp = p.parse("/abc");
- assertEquals(-1,pp.compareTo(null));
+ assertEquals(-1, pp.compareTo(null));
}
@Test
@@ -816,7 +819,7 @@ public class PathPatternMatcherTests {
assertEquals("/*/login.*", paths.get(1).getPatternString());
paths.clear();
}
-
+
@Test // SPR-13286
public void caseInsensitive() {
PathPatternParser pp = new PathPatternParser();
@@ -831,12 +834,12 @@ public class PathPatternMatcherTests {
public void patternmessage() {
PatternMessage[] values = PatternMessage.values();
assertNotNull(values);
- for (PatternMessage pm: values) {
+ for (PatternMessage pm : values) {
String name = pm.toString();
- assertEquals(pm.ordinal(),PatternMessage.valueOf(name).ordinal());
+ assertEquals(pm.ordinal(), PatternMessage.valueOf(name).ordinal());
}
}
-
+
private PathPattern parse(String path) {
PathPatternParser pp = new PathPatternParser();
return pp.parse(path);
@@ -869,7 +872,7 @@ public class PathPatternMatcherTests {
assertFalse(pattern.matches(path));
}
- private Map checkCapture(String uriTemplate, String path, String... keyValues) {
+ private Map checkCapture(String uriTemplate, String path, String... keyValues) {
PathPatternParser parser = new PathPatternParser();
PathPattern pattern = parser.parse(uriTemplate);
Map matchResults = pattern.matchAndExtract(path);
@@ -898,7 +901,7 @@ public class PathPatternMatcherTests {
PathPatternParser ppp = new PathPatternParser();
PathPattern pp = ppp.parse(pattern);
String s = pp.extractPathWithinPattern(path);
- assertEquals(expected,s);
+ assertEquals(expected, s);
}
static class TestPathCombiner {
diff --git a/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternParserTests.java b/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternParserTests.java
index 22bc6b4ac7..9729648dc0 100644
--- a/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternParserTests.java
+++ b/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.util.patterns;
import java.util.ArrayList;
@@ -26,13 +27,13 @@ import static org.junit.Assert.*;
/**
* Exercise the {@link PathPatternParser}.
- *
+ *
* @author Andy Clement
*/
public class PathPatternParserTests {
private PathPattern p;
-
+
@Test
public void basicPatterns() {
checkStructure("/");
@@ -42,23 +43,23 @@ public class PathPatternParserTests {
checkStructure("/foo/");
checkStructure("//");
}
-
+
@Test
public void singleCharWildcardPatterns() {
p = checkStructure("?");
- assertPathElements(p , SingleCharWildcardedPathElement.class);
+ assertPathElements(p, SingleCharWildcardedPathElement.class);
checkStructure("/?/");
checkStructure("//?abc?/");
}
-
+
@Test
public void multiwildcardPattern() {
p = checkStructure("/**");
- assertPathElements(p,WildcardTheRestPathElement.class);
+ assertPathElements(p, WildcardTheRestPathElement.class);
p = checkStructure("/**acb"); // this is not double wildcard use, it is / then **acb (an odd, unnecessary use of double *)
- assertPathElements(p,SeparatorPathElement.class, RegexPathElement.class);
+ assertPathElements(p, SeparatorPathElement.class, RegexPathElement.class);
}
-
+
@Test
public void toStringTests() {
assertEquals("CaptureTheRest(/{*foobar})", checkStructure("/{*foobar}").toChainString());
@@ -70,7 +71,7 @@ public class PathPatternParserTests {
assertEquals("Wildcard(*)", checkStructure("*").toChainString());
assertEquals("WildcardTheRest(/**)", checkStructure("/**").toChainString());
}
-
+
@Test
public void captureTheRestPatterns() {
checkError("/{*foobar}x{abc}", 10, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
@@ -81,13 +82,13 @@ public class PathPatternParserTests {
checkError("/{*foobar}/", 10, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
checkError("/{*foobar}abc", 10, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
checkError("/{*f%obar}", 4, PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
- checkError("/{*foobar}abc",10,PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
- checkError("/{f*oobar}",3,PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
- checkError("/{*foobar}/abc",10,PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
- checkError("/{abc}{*foobar}",1,PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
- checkError("/{abc}{*foobar}{foo}",15,PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
+ checkError("/{*foobar}abc", 10, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
+ checkError("/{f*oobar}", 3, PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
+ checkError("/{*foobar}/abc", 10, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
+ checkError("/{abc}{*foobar}", 1, PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
+ checkError("/{abc}{*foobar}{foo}", 15, PatternMessage.NO_MORE_DATA_EXPECTED_AFTER_CAPTURE_THE_REST);
}
-
+
@Test
public void equalsAndHashcode() {
PathPatternParser caseInsensitiveParser = new PathPatternParser();
@@ -96,23 +97,23 @@ public class PathPatternParserTests {
PathPattern pp1 = caseInsensitiveParser.parse("/abc");
PathPattern pp2 = caseInsensitiveParser.parse("/abc");
PathPattern pp3 = caseInsensitiveParser.parse("/def");
- assertEquals(pp1,pp2);
- assertEquals(pp1.hashCode(),pp2.hashCode());
+ assertEquals(pp1, pp2);
+ assertEquals(pp1.hashCode(), pp2.hashCode());
assertNotEquals(pp1, pp3);
assertFalse(pp1.equals("abc"));
-
+
pp1 = caseInsensitiveParser.parse("/abc");
pp2 = caseSensitiveParser.parse("/abc");
assertFalse(pp1.equals(pp2));
- assertNotEquals(pp1.hashCode(),pp2.hashCode());
-
+ assertNotEquals(pp1.hashCode(), pp2.hashCode());
+
PathPatternParser alternateSeparatorParser = new PathPatternParser(':');
pp1 = caseInsensitiveParser.parse("abc");
pp2 = alternateSeparatorParser.parse("abc");
assertFalse(pp1.equals(pp2));
- assertNotEquals(pp1.hashCode(),pp2.hashCode());
+ assertNotEquals(pp1.hashCode(), pp2.hashCode());
}
-
+
@Test
public void regexPathElementPatterns() {
checkError("/{var:[^/]*}", 8, PatternMessage.MISSING_CLOSE_CAPTURE);
@@ -120,78 +121,77 @@ public class PathPatternParserTests {
checkError("/{var:a{{1,2}}}", 6, PatternMessage.JDK_PATTERN_SYNTAX_EXCEPTION);
p = checkStructure("/{var:\\\\}");
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
assertTrue(p.matches("/\\"));
p = checkStructure("/{var:\\/}");
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
- assertFalse(p.matches("/aaa"));
-
- p = checkStructure("/{var:a{1,2}}",1);
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
-
- p = checkStructure("/{var:[^\\/]*}",1);
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
+ assertFalse(p.matches("/aaa"));
+
+ p = checkStructure("/{var:a{1,2}}", 1);
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
+
+ p = checkStructure("/{var:[^\\/]*}", 1);
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
Map result = p.matchAndExtract("/foo");
- assertEquals("foo",result.get("var"));
+ assertEquals("foo", result.get("var"));
- p = checkStructure("/{var:\\[*}",1);
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ p = checkStructure("/{var:\\[*}", 1);
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
result = p.matchAndExtract("/[[[");
- assertEquals("[[[",result.get("var"));
+ assertEquals("[[[", result.get("var"));
- p = checkStructure("/{var:[\\{]*}",1);
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ p = checkStructure("/{var:[\\{]*}", 1);
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
result = p.matchAndExtract("/{{{");
- assertEquals("{{{",result.get("var"));
+ assertEquals("{{{", result.get("var"));
- p = checkStructure("/{var:[\\}]*}",1);
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ p = checkStructure("/{var:[\\}]*}", 1);
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().next.getClass().getName());
result = p.matchAndExtract("/}}}");
- assertEquals("}}}",result.get("var"));
+ assertEquals("}}}", result.get("var"));
p = checkStructure("*");
- assertEquals(WildcardPathElement.class.getName(),p.getHeadSection().getClass().getName());
+ assertEquals(WildcardPathElement.class.getName(), p.getHeadSection().getClass().getName());
checkStructure("/*");
checkStructure("/*/");
checkStructure("*/");
checkStructure("/*/");
p = checkStructure("/*a*/");
- assertEquals(RegexPathElement.class.getName(),p.getHeadSection().next.getClass().getName());
+ assertEquals(RegexPathElement.class.getName(), p.getHeadSection().next.getClass().getName());
p = checkStructure("*/");
- assertEquals(WildcardPathElement.class.getName(),p.getHeadSection().getClass().getName());
+ assertEquals(WildcardPathElement.class.getName(), p.getHeadSection().getClass().getName());
checkError("{foo}_{foo}", 0, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, "foo");
checkError("/{bar}/{bar}", 7, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, "bar");
checkError("/{bar}/{bar}_{foo}", 7, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, "bar");
p = checkStructure("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar");
- assertEquals(RegexPathElement.class.getName(),p.getHeadSection().getClass().getName());
-
-
+ assertEquals(RegexPathElement.class.getName(), p.getHeadSection().getClass().getName());
+
}
-
+
@Test
public void completeCapturingPatterns() {
p = checkStructure("{foo}");
- assertEquals(CaptureVariablePathElement.class.getName(),p.getHeadSection().getClass().getName());
+ assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().getClass().getName());
checkStructure("/{foo}");
checkStructure("//{f}/");
checkStructure("/{foo}/{bar}/{wibble}");
}
-
+
@Test
public void completeCaptureWithConstraints() {
p = checkStructure("{foo:...}");
assertPathElements(p, CaptureVariablePathElement.class);
p = checkStructure("{foo:[0-9]*}");
assertPathElements(p, CaptureVariablePathElement.class);
- checkError("{foo:}",5,PatternMessage.MISSING_REGEX_CONSTRAINT);
+ checkError("{foo:}", 5, PatternMessage.MISSING_REGEX_CONSTRAINT);
}
@Test
public void partialCapturingPatterns() {
p = checkStructure("{foo}abc");
- assertEquals(RegexPathElement.class.getName(),p.getHeadSection().getClass().getName());
+ assertEquals(RegexPathElement.class.getName(), p.getHeadSection().getClass().getName());
checkStructure("abc{foo}");
checkStructure("/abc{foo}");
checkStructure("{foo}def/");
@@ -203,177 +203,179 @@ public class PathPatternParserTests {
@Test
public void illegalCapturePatterns() {
- checkError("{abc/",4,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("{abc:}/",5,PatternMessage.MISSING_REGEX_CONSTRAINT);
- checkError("{",1,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("{abc",4,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("{/}",1,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("//{",3,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("}",0,PatternMessage.MISSING_OPEN_CAPTURE);
- checkError("/}",1,PatternMessage.MISSING_OPEN_CAPTURE);
- checkError("def}",3,PatternMessage.MISSING_OPEN_CAPTURE);
- checkError("//{/}",3,PatternMessage.MISSING_CLOSE_CAPTURE);
- checkError("//{{/}",3,PatternMessage.ILLEGAL_NESTED_CAPTURE);
- checkError("//{abc{/}",6,PatternMessage.ILLEGAL_NESTED_CAPTURE);
- checkError("/{0abc}/abc",2,PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR);
- checkError("/{a?bc}/abc",3,PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
- checkError("/{abc}_{abc}",1,PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
- checkError("/foobar/{abc}_{abc}",8,PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
- checkError("/foobar/{abc:..}_{abc:..}",8,PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
+ checkError("{abc/", 4, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("{abc:}/", 5, PatternMessage.MISSING_REGEX_CONSTRAINT);
+ checkError("{", 1, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("{abc", 4, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("{/}", 1, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("//{", 3, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("}", 0, PatternMessage.MISSING_OPEN_CAPTURE);
+ checkError("/}", 1, PatternMessage.MISSING_OPEN_CAPTURE);
+ checkError("def}", 3, PatternMessage.MISSING_OPEN_CAPTURE);
+ checkError("//{/}", 3, PatternMessage.MISSING_CLOSE_CAPTURE);
+ checkError("//{{/}", 3, PatternMessage.ILLEGAL_NESTED_CAPTURE);
+ checkError("//{abc{/}", 6, PatternMessage.ILLEGAL_NESTED_CAPTURE);
+ checkError("/{0abc}/abc", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR);
+ checkError("/{a?bc}/abc", 3, PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
+ checkError("/{abc}_{abc}", 1, PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
+ checkError("/foobar/{abc}_{abc}", 8, PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
+ checkError("/foobar/{abc:..}_{abc:..}", 8, PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
PathPattern pp = parse("/{abc:foo(bar)}");
try {
pp.matchAndExtract("/foo");
fail("Should have raised exception");
- } catch (IllegalArgumentException iae) {
- assertEquals("No capture groups allowed in the constraint regex: foo(bar)",iae.getMessage());
+ }
+ catch (IllegalArgumentException iae) {
+ assertEquals("No capture groups allowed in the constraint regex: foo(bar)", iae.getMessage());
}
try {
pp.matchAndExtract("/foobar");
fail("Should have raised exception");
- } catch (IllegalArgumentException iae) {
- assertEquals("No capture groups allowed in the constraint regex: foo(bar)",iae.getMessage());
+ }
+ catch (IllegalArgumentException iae) {
+ assertEquals("No capture groups allowed in the constraint regex: foo(bar)", iae.getMessage());
}
}
@Test
public void badPatterns() {
// checkError("/{foo}{bar}/",6,PatternMessage.CANNOT_HAVE_ADJACENT_CAPTURES);
- checkError("/{?}/",2,PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR,"?");
- checkError("/{a?b}/",3,PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR,"?");
- checkError("/{%%$}",2,PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR,"%");
- checkError("/{ }",2,PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR," ");
- checkError("/{%:[0-9]*}",2,PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR,"%");
+ checkError("/{?}/", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR, "?");
+ checkError("/{a?b}/", 3, PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR, "?");
+ checkError("/{%%$}", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR, "%");
+ checkError("/{ }", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR, " ");
+ checkError("/{%:[0-9]*}", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR, "%");
}
-
+
@Test
public void patternPropertyGetCaptureCountTests() {
// Test all basic section types
- assertEquals(1,parse("{foo}").getCapturedVariableCount());
- assertEquals(0,parse("foo").getCapturedVariableCount());
- assertEquals(1,parse("{*foobar}").getCapturedVariableCount());
- assertEquals(1,parse("/{*foobar}").getCapturedVariableCount());
- assertEquals(0,parse("/**").getCapturedVariableCount());
- assertEquals(1,parse("{abc}asdf").getCapturedVariableCount());
- assertEquals(1,parse("{abc}_*").getCapturedVariableCount());
- assertEquals(2,parse("{abc}_{def}").getCapturedVariableCount());
- assertEquals(0,parse("/").getCapturedVariableCount());
- assertEquals(0,parse("a?b").getCapturedVariableCount());
- assertEquals(0,parse("*").getCapturedVariableCount());
+ assertEquals(1, parse("{foo}").getCapturedVariableCount());
+ assertEquals(0, parse("foo").getCapturedVariableCount());
+ assertEquals(1, parse("{*foobar}").getCapturedVariableCount());
+ assertEquals(1, parse("/{*foobar}").getCapturedVariableCount());
+ assertEquals(0, parse("/**").getCapturedVariableCount());
+ assertEquals(1, parse("{abc}asdf").getCapturedVariableCount());
+ assertEquals(1, parse("{abc}_*").getCapturedVariableCount());
+ assertEquals(2, parse("{abc}_{def}").getCapturedVariableCount());
+ assertEquals(0, parse("/").getCapturedVariableCount());
+ assertEquals(0, parse("a?b").getCapturedVariableCount());
+ assertEquals(0, parse("*").getCapturedVariableCount());
// Test on full templates
- assertEquals(0,parse("/foo/bar").getCapturedVariableCount());
- assertEquals(1,parse("/{foo}").getCapturedVariableCount());
- assertEquals(2,parse("/{foo}/{bar}").getCapturedVariableCount());
- assertEquals(4,parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getCapturedVariableCount());
+ assertEquals(0, parse("/foo/bar").getCapturedVariableCount());
+ assertEquals(1, parse("/{foo}").getCapturedVariableCount());
+ assertEquals(2, parse("/{foo}/{bar}").getCapturedVariableCount());
+ assertEquals(4, parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getCapturedVariableCount());
}
-
+
@Test
public void patternPropertyGetWildcardCountTests() {
// Test all basic section types
- assertEquals(computeScore(1,0),parse("{foo}").getScore());
- assertEquals(computeScore(0,0),parse("foo").getScore());
- assertEquals(computeScore(0,0),parse("{*foobar}").getScore());
+ assertEquals(computeScore(1, 0), parse("{foo}").getScore());
+ assertEquals(computeScore(0, 0), parse("foo").getScore());
+ assertEquals(computeScore(0, 0), parse("{*foobar}").getScore());
// assertEquals(1,parse("/**").getScore());
- assertEquals(computeScore(1,0),parse("{abc}asdf").getScore());
- assertEquals(computeScore(1,1),parse("{abc}_*").getScore());
- assertEquals(computeScore(2,0),parse("{abc}_{def}").getScore());
- assertEquals(computeScore(0,0),parse("/").getScore());
- assertEquals(computeScore(0,0),parse("a?b").getScore()); // currently deliberate
- assertEquals(computeScore(0,1),parse("*").getScore());
+ assertEquals(computeScore(1, 0), parse("{abc}asdf").getScore());
+ assertEquals(computeScore(1, 1), parse("{abc}_*").getScore());
+ assertEquals(computeScore(2, 0), parse("{abc}_{def}").getScore());
+ assertEquals(computeScore(0, 0), parse("/").getScore());
+ assertEquals(computeScore(0, 0), parse("a?b").getScore()); // currently deliberate
+ assertEquals(computeScore(0, 1), parse("*").getScore());
// Test on full templates
- assertEquals(computeScore(0,0),parse("/foo/bar").getScore());
- assertEquals(computeScore(1,0),parse("/{foo}").getScore());
- assertEquals(computeScore(2,0),parse("/{foo}/{bar}").getScore());
- assertEquals(computeScore(4,0),parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getScore());
- assertEquals(computeScore(4,3),parse("/{foo}/*/*_*/{bar}_{goo}_{wibble}/abc/bar").getScore());
+ assertEquals(computeScore(0, 0), parse("/foo/bar").getScore());
+ assertEquals(computeScore(1, 0), parse("/{foo}").getScore());
+ assertEquals(computeScore(2, 0), parse("/{foo}/{bar}").getScore());
+ assertEquals(computeScore(4, 0), parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getScore());
+ assertEquals(computeScore(4, 3), parse("/{foo}/*/*_*/{bar}_{goo}_{wibble}/abc/bar").getScore());
}
-
+
@Test
public void multipleSeparatorPatterns() {
p = checkStructure("///aaa");
- assertEquals(4,p.getNormalizedLength());
- assertPathElements(p,SeparatorPathElement.class,LiteralPathElement.class);
+ assertEquals(4, p.getNormalizedLength());
+ assertPathElements(p, SeparatorPathElement.class, LiteralPathElement.class);
p = checkStructure("///aaa////aaa/b");
- assertEquals(10,p.getNormalizedLength());
- assertPathElements(p,SeparatorPathElement.class, LiteralPathElement.class,
+ assertEquals(10, p.getNormalizedLength());
+ assertPathElements(p, SeparatorPathElement.class, LiteralPathElement.class,
SeparatorPathElement.class, LiteralPathElement.class, SeparatorPathElement.class, LiteralPathElement.class);
p = checkStructure("/////**");
- assertEquals(1,p.getNormalizedLength());
- assertPathElements(p,WildcardTheRestPathElement.class);
+ assertEquals(1, p.getNormalizedLength());
+ assertPathElements(p, WildcardTheRestPathElement.class);
}
-
+
@Test
public void patternPropertyGetLengthTests() {
// Test all basic section types
- assertEquals(1,parse("{foo}").getNormalizedLength());
- assertEquals(3,parse("foo").getNormalizedLength());
- assertEquals(1,parse("{*foobar}").getNormalizedLength());
- assertEquals(1,parse("/{*foobar}").getNormalizedLength());
- assertEquals(1,parse("/**").getNormalizedLength());
- assertEquals(5,parse("{abc}asdf").getNormalizedLength());
- assertEquals(3,parse("{abc}_*").getNormalizedLength());
- assertEquals(3,parse("{abc}_{def}").getNormalizedLength());
- assertEquals(1,parse("/").getNormalizedLength());
- assertEquals(3,parse("a?b").getNormalizedLength());
- assertEquals(1,parse("*").getNormalizedLength());
+ assertEquals(1, parse("{foo}").getNormalizedLength());
+ assertEquals(3, parse("foo").getNormalizedLength());
+ assertEquals(1, parse("{*foobar}").getNormalizedLength());
+ assertEquals(1, parse("/{*foobar}").getNormalizedLength());
+ assertEquals(1, parse("/**").getNormalizedLength());
+ assertEquals(5, parse("{abc}asdf").getNormalizedLength());
+ assertEquals(3, parse("{abc}_*").getNormalizedLength());
+ assertEquals(3, parse("{abc}_{def}").getNormalizedLength());
+ assertEquals(1, parse("/").getNormalizedLength());
+ assertEquals(3, parse("a?b").getNormalizedLength());
+ assertEquals(1, parse("*").getNormalizedLength());
// Test on full templates
- assertEquals(8,parse("/foo/bar").getNormalizedLength());
- assertEquals(2,parse("/{foo}").getNormalizedLength());
- assertEquals(4,parse("/{foo}/{bar}").getNormalizedLength());
- assertEquals(16,parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getNormalizedLength());
+ assertEquals(8, parse("/foo/bar").getNormalizedLength());
+ assertEquals(2, parse("/{foo}").getNormalizedLength());
+ assertEquals(4, parse("/{foo}/{bar}").getNormalizedLength());
+ assertEquals(16, parse("/{foo}/{bar}_{goo}_{wibble}/abc/bar").getNormalizedLength());
}
-
+
@Test
public void compareTests() {
- PathPattern p1,p2,p3;
-
+ PathPattern p1, p2, p3;
+
// Based purely on number of captures
p1 = parse("{a}");
p2 = parse("{a}/{b}");
p3 = parse("{a}/{b}/{c}");
- assertEquals(-1,p1.compareTo(p2)); // Based on number of captures
+ assertEquals(-1, p1.compareTo(p2)); // Based on number of captures
List patterns = new ArrayList<>();
patterns.add(p2);
patterns.add(p3);
patterns.add(p1);
- Collections.sort(patterns,new PathPatternComparator());
- assertEquals(p1,patterns.get(0));
-
+ Collections.sort(patterns, new PathPatternComparator());
+ assertEquals(p1, patterns.get(0));
+
// Based purely on length
p1 = parse("/a/b/c");
p2 = parse("/a/boo/c/doo");
p3 = parse("/asdjflaksjdfjasdf");
- assertEquals(1,p1.compareTo(p2));
+ assertEquals(1, p1.compareTo(p2));
patterns = new ArrayList<>();
patterns.add(p2);
patterns.add(p3);
patterns.add(p1);
- Collections.sort(patterns,new PathPatternComparator());
- assertEquals(p3,patterns.get(0));
-
+ Collections.sort(patterns, new PathPatternComparator());
+ assertEquals(p3, patterns.get(0));
+
// Based purely on 'wildness'
p1 = parse("/*");
p2 = parse("/*/*");
p3 = parse("/*/*/*_*");
- assertEquals(-1,p1.compareTo(p2));
+ assertEquals(-1, p1.compareTo(p2));
patterns = new ArrayList<>();
patterns.add(p2);
patterns.add(p3);
patterns.add(p1);
- Collections.sort(patterns,new PathPatternComparator());
- assertEquals(p1,patterns.get(0));
+ Collections.sort(patterns, new PathPatternComparator());
+ assertEquals(p1, patterns.get(0));
// Based purely on catchAll
p1 = parse("{*foobar}");
p2 = parse("{*goo}");
- assertEquals(0,p1.compareTo(p2));
-
+ assertEquals(0, p1.compareTo(p2));
+
p1 = parse("/{*foobar}");
p2 = parse("/abc/{*ww}");
- assertEquals(+1,p1.compareTo(p2));
- assertEquals(-1,p2.compareTo(p1));
+ assertEquals(+1, p1.compareTo(p2));
+ assertEquals(-1, p2.compareTo(p1));
p3 = parse("/this/that/theother");
assertTrue(p1.isCatchAll());
@@ -383,20 +385,20 @@ public class PathPatternParserTests {
patterns.add(p2);
patterns.add(p3);
patterns.add(p1);
- Collections.sort(patterns,new PathPatternComparator());
- assertEquals(p3,patterns.get(0));
- assertEquals(p2,patterns.get(1));
-
+ Collections.sort(patterns, new PathPatternComparator());
+ assertEquals(p3, patterns.get(0));
+ assertEquals(p2, patterns.get(1));
+
patterns = new ArrayList<>();
patterns.add(parse("/abc"));
patterns.add(null);
patterns.add(parse("/def"));
- Collections.sort(patterns,new PathPatternComparator());
+ Collections.sort(patterns, new PathPatternComparator());
assertNull(patterns.get(2));
}
// ---
-
+
private PathPattern parse(String pattern) {
PathPatternParser patternParser = new PathPatternParser();
return patternParser.parse(pattern);
@@ -408,22 +410,22 @@ public class PathPatternParserTests {
*/
private PathPattern checkStructure(String pattern) {
int count = 0;
- for (int i=0;i... sectionClasses) {
PathElement head = p.getHeadSection();
- for (int i=0;i