WebFlux compiles after PathPattern/Container changes

This commit is contained in:
Rossen Stoyanchev
2017-06-30 11:03:36 -04:00
parent 26448a0ebc
commit 8581afa621
9 changed files with 220 additions and 269 deletions

View File

@@ -19,10 +19,10 @@ package org.springframework.web.util.pattern;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.lang.Nullable;
@@ -79,19 +79,17 @@ public class ParsingPathMatcher implements PathMatcher {
@Override
public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
PathPattern pathPattern = getPathPattern(pattern);
Map<String, PathMatchResult> results = pathPattern.matchAndExtract(PathContainer.parse(path, StandardCharsets.UTF_8));
// Collapse PathMatchResults to simple value results (path parameters are lost in this translation)
Map<String, String> boundVariables = null;
if (results.size() == 0) {
boundVariables = Collections.emptyMap();
PathContainer pathContainer = PathContainer.parse(path, StandardCharsets.UTF_8);
PathMatchResult results = pathPattern.matchAndExtract(pathContainer);
// Collapse PathMatchResults to simple value results
// TODO: (path parameters are lost in this translation)
if (results.getUriVariables().size() == 0) {
return Collections.emptyMap();
}
else {
boundVariables = new LinkedHashMap<>();
for (Map.Entry<String,PathMatchResult> entries: results.entrySet()) {
boundVariables.put(entries.getKey(), entries.getValue().value());
}
return results.getUriVariables().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
return boundVariables;
}
@Override

View File

@@ -27,6 +27,7 @@ import org.springframework.http.server.reactive.PathContainer.Element;
import org.springframework.http.server.reactive.PathContainer.Segment;
import org.springframework.http.server.reactive.PathContainer.Separator;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
@@ -155,6 +156,26 @@ public class PathPattern implements Comparable<PathPattern> {
return this.patternString;
}
// TODO: remove String-variants
public boolean matches(String path) {
return matches(PathContainer.parse(path, StandardCharsets.UTF_8));
}
public PathMatchResult matchAndExtract(String path) {
return matchAndExtract(PathContainer.parse(path, StandardCharsets.UTF_8));
}
@Nullable
public PathRemainingMatchInfo getPathRemaining(@Nullable String path) {
return getPathRemaining(path != null ?
PathContainer.parse(path, StandardCharsets.UTF_8) : null);
}
/**
* @param pathContainer the candidate path container to attempt to match against this pattern
* @return true if the path matches this pattern
@@ -199,11 +220,11 @@ public class PathPattern implements Comparable<PathPattern> {
else {
PathRemainingMatchInfo info;
if (matchingContext.remainingPathIndex == pathContainer.elements().size()) {
info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getExtractedVariables());
info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getPathMatchResult());
}
else {
info = new PathRemainingMatchInfo(PathContainer.subPath(pathContainer, matchingContext.remainingPathIndex),
matchingContext.getExtractedVariables());
matchingContext.getPathMatchResult());
}
return info;
}
@@ -230,13 +251,13 @@ public class PathPattern implements Comparable<PathPattern> {
* @return a map of extracted variables - an empty map if no variables extracted.
* @throws IllegalStateException if the path does not match the pattern
*/
public Map<String, PathMatchResult> matchAndExtract(PathContainer pathContainer) {
public PathMatchResult matchAndExtract(PathContainer pathContainer) {
MatchingContext matchingContext = new MatchingContext(pathContainer, true);
if (this.head != null && this.head.matches(0, matchingContext)) {
return matchingContext.getExtractedVariables();
return matchingContext.getPathMatchResult();
}
else if (!hasLength(pathContainer)) {
return Collections.emptyMap();
return PathMatchResult.EMPTY;
}
else {
throw new IllegalStateException("Pattern \"" + this + "\" is not a match for \"" + pathContainer.value() + "\"");
@@ -447,45 +468,46 @@ public class PathPattern implements Comparable<PathPattern> {
return this.patternString;
}
/**
* Represents the result of a successful variable match. This holds the key that matched, the
* value that was found for that key and, if any, the parameters attached to that path element.
* For example: "/{var}" against "/foo;a=b" will return a PathMathResult with 'key=var',
* 'value=foo' and parameters 'a=b'.
* Represents the result of a successful path match. This holds the keys that matched, the
* values that were found for each key and, if any, the path parameters (matrix variables)
* attached to that path element.
* For example: "/{var}" against "/foo;a=b" will return a PathMathResult with 'foo=bar'
* for URI variables and 'a=b' as path parameters for 'foo'.
*/
public static class PathMatchResult {
private final String key;
private final String value;
private final MultiValueMap<String,String> parameters;
public PathMatchResult(String key, String value, MultiValueMap<String, String> parameters) {
this.key = key;
this.value = value;
this.parameters = parameters;
private static final PathMatchResult EMPTY =
new PathMatchResult(Collections.emptyMap(), Collections.emptyMap());
private final Map<String, String> uriVariables;
private final Map<String, MultiValueMap<String, String>> matrixVariables;
public PathMatchResult(Map<String, String> uriVars,
@Nullable Map<String, MultiValueMap<String, String>> matrixVars) {
this.uriVariables = Collections.unmodifiableMap(uriVars);
this.matrixVariables = matrixVars != null ?
Collections.unmodifiableMap(matrixVars) : Collections.emptyMap();
}
/**
* @return match result key
*/
public String key() {
return key;
public Map<String, String> getUriVariables() {
return this.uriVariables;
}
/**
* @return match result value
*/
public String value() {
return this.value;
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
return this.matrixVariables;
}
/**
* @return match result parameters (empty map if no parameters)
*/
public MultiValueMap<String,String> parameters() {
return this.parameters;
@Override
public String toString() {
return "PathMatchResult[uriVariables=" + this.uriVariables + ", " +
"matrixVariables=" + this.matrixVariables + "]";
}
}
@@ -498,15 +520,15 @@ public class PathPattern implements Comparable<PathPattern> {
private final PathContainer pathRemaining;
private final Map<String, PathMatchResult> matchingVariables;
private final PathMatchResult pathMatchResult;
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining) {
this(pathRemaining, Collections.emptyMap());
this(pathRemaining, PathMatchResult.EMPTY);
}
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining, Map<String, PathMatchResult> matchingVariables) {
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining, PathMatchResult pathMatchResult) {
this.pathRemaining = pathRemaining;
this.matchingVariables = matchingVariables;
this.pathMatchResult = pathMatchResult;
}
/**
@@ -520,8 +542,15 @@ public class PathPattern implements Comparable<PathPattern> {
* Return variables that were bound in the part of the path that was successfully matched.
* Will be an empty map if no variables were bound
*/
public Map<String, PathMatchResult> getMatchingVariables() {
return this.matchingVariables;
public Map<String, String> getUriVariables() {
return this.pathMatchResult.getUriVariables();
}
/**
* Return the path parameters for each bound variable.
*/
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
return this.pathMatchResult.getMatrixVariables();
}
}
@@ -595,7 +624,10 @@ public class PathPattern implements Comparable<PathPattern> {
boolean isMatchStartMatching = false;
@Nullable
private Map<String, PathMatchResult> extractedVariables;
private Map<String, String> extractedUriVariables;
@Nullable
private Map<String, MultiValueMap<String, String>> extractedMatrixVariables;
boolean extractingVariables;
@@ -626,18 +658,25 @@ public class PathPattern implements Comparable<PathPattern> {
}
public void set(String key, String value, MultiValueMap<String,String> parameters) {
if (this.extractedVariables == null) {
extractedVariables = new HashMap<>();
if (this.extractedUriVariables == null) {
this.extractedUriVariables = new HashMap<>();
}
this.extractedUriVariables.put(key, value);
if (!parameters.isEmpty()) {
if (this.extractedMatrixVariables == null) {
this.extractedMatrixVariables = new HashMap<>();
}
this.extractedMatrixVariables.put(key, CollectionUtils.unmodifiableMultiValueMap(parameters));
}
extractedVariables.put(key, new PathMatchResult(key, value, parameters));
}
public Map<String, PathMatchResult> getExtractedVariables() {
if (this.extractedVariables == null) {
return Collections.emptyMap();
public PathMatchResult getPathMatchResult() {
if (this.extractedUriVariables == null) {
return PathMatchResult.EMPTY;
}
else {
return this.extractedVariables;
return new PathMatchResult(this.extractedUriVariables, this.extractedMatrixVariables);
}
}

View File

@@ -29,17 +29,20 @@ import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.http.server.reactive.PathContainer.Element;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.util.pattern.ParsingPathMatcher;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
import org.springframework.web.util.pattern.PathPattern.PathRemainingMatchInfo;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Exercise matching of {@link PathPattern} objects.
@@ -125,26 +128,26 @@ public class PathPatternMatcherTests {
// CaptureVariablePathElement
pp = parse("/{var}");
assertMatches(pp,"/resource");
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
assertMatches(pp,"/resource/");
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
assertNoMatch(pp,"/resource//");
pp = parse("/{var}/");
assertNoMatch(pp,"/resource");
assertMatches(pp,"/resource/");
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
assertNoMatch(pp,"/resource//");
// CaptureTheRestPathElement
pp = parse("/{*var}");
assertMatches(pp,"/resource");
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
assertMatches(pp,"/resource/");
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
assertMatches(pp,"/resource//");
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).get("var").value());
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).getUriVariables().get("var"));
assertMatches(pp,"//resource//");
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).get("var").value());
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).getUriVariables().get("var"));
// WildcardTheRestPathElement
pp = parse("/**");
@@ -166,17 +169,17 @@ public class PathPatternMatcherTests {
// RegexPathElement
pp = parse("/{var1}_{var2}");
assertMatches(pp,"/res1_res2");
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var1").value());
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var2").value());
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var1"));
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var2"));
assertMatches(pp,"/res1_res2/");
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
assertNoMatch(pp,"/res1_res2//");
pp = parse("/{var1}_{var2}/");
assertNoMatch(pp,"/res1_res2");
assertMatches(pp,"/res1_res2/");
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
assertNoMatch(pp,"/res1_res2//");
pp = parse("/{var1}*");
assertMatches(pp,"/a");
@@ -210,25 +213,25 @@ public class PathPatternMatcherTests {
// CaptureVariablePathElement
pp = parser.parse("/{var}");
assertMatches(pp,"/resource");
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
assertNoMatch(pp,"/resource/");
assertNoMatch(pp,"/resource//");
pp = parser.parse("/{var}/");
assertNoMatch(pp,"/resource");
assertMatches(pp,"/resource/");
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
assertNoMatch(pp,"/resource//");
// CaptureTheRestPathElement
pp = parser.parse("/{*var}");
assertMatches(pp,"/resource");
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
assertMatches(pp,"/resource/");
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
assertMatches(pp,"/resource//");
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).get("var").value());
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).getUriVariables().get("var"));
assertMatches(pp,"//resource//");
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).get("var").value());
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).getUriVariables().get("var"));
// WildcardTheRestPathElement
pp = parser.parse("/**");
@@ -250,15 +253,15 @@ public class PathPatternMatcherTests {
// RegexPathElement
pp = parser.parse("/{var1}_{var2}");
assertMatches(pp,"/res1_res2");
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var1").value());
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var2").value());
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var1"));
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var2"));
assertNoMatch(pp,"/res1_res2/");
assertNoMatch(pp,"/res1_res2//");
pp = parser.parse("/{var1}_{var2}/");
assertNoMatch(pp,"/res1_res2");
assertMatches(pp,"/res1_res2/");
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
assertNoMatch(pp,"/res1_res2//");
pp = parser.parse("/{var1}*");
assertMatches(pp,"/a");
@@ -337,23 +340,23 @@ public class PathPatternMatcherTests {
PathPattern.PathRemainingMatchInfo pri = parse("/aaa/{bbb}/c?d/e*f/*/g").getPathRemaining(toPathContainer("/aaa/b/ccd/ef/x/g/i"));
assertEquals("/i",pri.getPathRemaining());
assertEquals("b",pri.getMatchingVariables().get("bbb").value());
assertEquals("b",pri.getUriVariables().get("bbb"));
pri = parse("/aaa/{bbb}/c?d/e*f/*/g/").getPathRemaining(toPathContainer("/aaa/b/ccd/ef/x/g/i"));
assertEquals("i",pri.getPathRemaining());
assertEquals("b",pri.getMatchingVariables().get("bbb").value());
assertEquals("b",pri.getUriVariables().get("bbb"));
pri = parse("/{aaa}_{bbb}/e*f/{x}/g").getPathRemaining(toPathContainer("/aa_bb/ef/x/g/i"));
assertEquals("/i",pri.getPathRemaining());
assertEquals("aa",pri.getMatchingVariables().get("aaa").value());
assertEquals("bb",pri.getMatchingVariables().get("bbb").value());
assertEquals("x",pri.getMatchingVariables().get("x").value());
assertEquals("aa",pri.getUriVariables().get("aaa"));
assertEquals("bb",pri.getUriVariables().get("bbb"));
assertEquals("x",pri.getUriVariables().get("x"));
assertNull(parse("/a/b").getPathRemaining(toPathContainer("")));
assertNull(parse("/a/b").getPathRemaining(null));
assertNull(parse("/a/b").getPathRemaining((String) null));
assertEquals("/a/b",parse("").getPathRemaining(toPathContainer("/a/b")).getPathRemaining());
assertEquals("",parse("").getPathRemaining(toPathContainer("")).getPathRemaining());
assertNull(parse("").getPathRemaining(null).getPathRemaining());
assertNull(parse("").getPathRemaining((String) null).getPathRemaining());
}
@Test
@@ -550,30 +553,30 @@ public class PathPatternMatcherTests {
pp = parse("/{this}/{one}/{here}");
pri = getPathRemaining(pp, "/foo/bar/goo/boo");
assertEquals("/boo",pri.getPathRemaining());
assertEquals("foo",pri.getMatchingVariables().get("this").value());
assertEquals("bar",pri.getMatchingVariables().get("one").value());
assertEquals("goo",pri.getMatchingVariables().get("here").value());
assertEquals("foo",pri.getUriVariables().get("this"));
assertEquals("bar",pri.getUriVariables().get("one"));
assertEquals("goo",pri.getUriVariables().get("here"));
pp = parse("/aaa/{foo}");
pri = getPathRemaining(pp, "/aaa/bbb");
assertEquals("",pri.getPathRemaining());
assertEquals("bbb",pri.getMatchingVariables().get("foo").value());
assertEquals("bbb",pri.getUriVariables().get("foo"));
pp = parse("/aaa/bbb");
pri = getPathRemaining(pp, "/aaa/bbb");
assertEquals("",pri.getPathRemaining());
assertEquals(0,pri.getMatchingVariables().size());
assertEquals(0,pri.getUriVariables().size());
pp = parse("/*/{foo}/b*");
pri = getPathRemaining(pp, "/foo");
assertNull(pri);
pri = getPathRemaining(pp, "/abc/def/bhi");
assertEquals("",pri.getPathRemaining());
assertEquals("def",pri.getMatchingVariables().get("foo").value());
assertEquals("def",pri.getUriVariables().get("foo"));
pri = getPathRemaining(pp, "/abc/def/bhi/jkl");
assertEquals("/jkl",pri.getPathRemaining());
assertEquals("def",pri.getMatchingVariables().get("foo").value());
assertEquals("def",pri.getUriVariables().get("foo"));
}
@Test
@@ -953,7 +956,7 @@ public class PathPatternMatcherTests {
catch (IllegalStateException e) {
assertEquals("Pattern \"\" is not a match for \"/abc\"", e.getMessage());
}
assertEquals(0, checkCapture("", "").size());
assertEquals(0, checkCapture("", "").getUriVariables().size());
checkCapture("{id}", "99", "id", "99");
checkCapture("/customer/{customerId}", "/customer/78", "customerId", "78");
checkCapture("/customer/{customerId}/banana", "/customer/42/banana", "customerId",
@@ -962,8 +965,8 @@ public class PathPatternMatcherTests {
checkCapture("/foo/{bar}/boo/{baz}", "/foo/plum/boo/apple", "bar", "plum", "baz",
"apple");
checkCapture("/{bla}.*", "/testing.html", "bla", "testing");
Map<String, PathMatchResult> extracted = checkCapture("/abc", "/abc");
assertEquals(0, extracted.size());
PathMatchResult extracted = checkCapture("/abc", "/abc");
assertEquals(0, extracted.getUriVariables().size());
checkCapture("/{bla}/foo","/a/foo");
}
@@ -973,14 +976,14 @@ public class PathPatternMatcherTests {
PathPattern p = null;
p = pp.parse("{symbolicName:[\\w\\.]+}-{version:[\\w\\.]+}.jar");
Map<String, PathMatchResult> result = matchAndExtract(p, "com.example-1.0.0.jar");
assertEquals("com.example", result.get("symbolicName").value());
assertEquals("1.0.0", result.get("version").value());
PathMatchResult result = matchAndExtract(p, "com.example-1.0.0.jar");
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
assertEquals("1.0.0", result.getUriVariables().get("version"));
p = pp.parse("{symbolicName:[\\w\\.]+}-sources-{version:[\\w\\.]+}.jar");
result = matchAndExtract(p, "com.example-sources-1.0.0.jar");
assertEquals("com.example", result.get("symbolicName").value());
assertEquals("1.0.0", result.get("version").value());
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
assertEquals("1.0.0", result.getUriVariables().get("version"));
}
@Test
@@ -988,22 +991,22 @@ public class PathPatternMatcherTests {
PathPatternParser pp = new PathPatternParser();
PathPattern p = pp.parse("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar");
Map<String, PathMatchResult> result = p.matchAndExtract(toPathContainer("com.example-sources-1.0.0.jar"));
assertEquals("com.example", result.get("symbolicName").value());
assertEquals("1.0.0", result.get("version").value());
PathMatchResult result = p.matchAndExtract(toPathContainer("com.example-sources-1.0.0.jar"));
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
assertEquals("1.0.0", result.getUriVariables().get("version"));
p = pp.parse("{symbolicName:[\\w\\.]+}-sources-{version:[\\d\\.]+}-{year:\\d{4}}{month:\\d{2}}{day:\\d{2}}.jar");
result = matchAndExtract(p,"com.example-sources-1.0.0-20100220.jar");
assertEquals("com.example", result.get("symbolicName").value());
assertEquals("1.0.0", result.get("version").value());
assertEquals("2010", result.get("year").value());
assertEquals("02", result.get("month").value());
assertEquals("20", result.get("day").value());
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
assertEquals("1.0.0", result.getUriVariables().get("version"));
assertEquals("2010", result.getUriVariables().get("year"));
assertEquals("02", result.getUriVariables().get("month"));
assertEquals("20", result.getUriVariables().get("day"));
p = pp.parse("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.\\{\\}]+}.jar");
result = matchAndExtract(p, "com.example-sources-1.0.0.{12}.jar");
assertEquals("com.example", result.get("symbolicName").value());
assertEquals("1.0.0.{12}", result.get("version").value());
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
assertEquals("1.0.0.{12}", result.getUriVariables().get("version"));
}
@Test
@@ -1137,12 +1140,12 @@ public class PathPatternMatcherTests {
PathPatternParser parser = new PathPatternParser();
PathPattern p1 = parser.parse("/{foo}");
PathPattern p2 = parser.parse("/{foo}.*");
Map<String, PathMatchResult> r1 = matchAndExtract(p1, "/file.txt");
Map<String, PathMatchResult> r2 = matchAndExtract(p2, "/file.txt");
PathMatchResult r1 = matchAndExtract(p1, "/file.txt");
PathMatchResult r2 = matchAndExtract(p2, "/file.txt");
// works fine
assertEquals("file.txt", r1.get("foo").value());
assertEquals("file", r2.get("foo").value());
assertEquals("file.txt", r1.getUriVariables().get("foo"));
assertEquals("file", r2.getUriVariables().get("foo"));
// This produces 2 (see comments in https://jira.spring.io/browse/SPR-14544 )
// Comparator<String> patternComparator = new AntPathMatcher().getPatternComparator("");
@@ -1269,38 +1272,38 @@ public class PathPatternMatcherTests {
@Test
public void parameters() {
// CaptureVariablePathElement
Map<String, PathMatchResult> result = matchAndExtract("/abc/{var}","/abc/one;two=three;four=five");
assertEquals("one",result.get("var").value());
assertEquals("[three]",result.get("var").parameters().get("two").toString());
assertEquals("[five]",result.get("var").parameters().get("four").toString());
PathMatchResult result = matchAndExtract("/abc/{var}","/abc/one;two=three;four=five");
assertEquals("one",result.getUriVariables().get("var"));
assertEquals("three",result.getMatrixVariables().get("var").getFirst("two"));
assertEquals("five",result.getMatrixVariables().get("var").getFirst("four"));
// RegexPathElement
result = matchAndExtract("/abc/{var1}_{var2}","/abc/123_456;a=b;c=d");
assertEquals("123",result.get("var1").value());
assertEquals("456",result.get("var2").value());
assertEquals("123",result.getUriVariables().get("var1"));
assertEquals("456",result.getUriVariables().get("var2"));
// vars associated with second variable
assertNull(result.get("var1").parameters().get("a"));
assertNull(result.get("var1").parameters().get("c"));
assertEquals("[b]",result.get("var2").parameters().get("a").toString());
assertEquals("[d]",result.get("var2").parameters().get("c").toString());
assertNull(result.getMatrixVariables().get("var1"));
assertNull(result.getMatrixVariables().get("var1"));
assertEquals("b",result.getMatrixVariables().get("var2").getFirst("a"));
assertEquals("d",result.getMatrixVariables().get("var2").getFirst("c"));
// CaptureTheRestPathElement
result = matchAndExtract("/{*var}","/abc/123_456;a=b;c=d");
assertEquals("/abc/123_456",result.get("var").value());
assertEquals("[b]",result.get("var").parameters().get("a").toString());
assertEquals("[d]",result.get("var").parameters().get("c").toString());
assertEquals("/abc/123_456",result.getUriVariables().get("var"));
assertEquals("b",result.getMatrixVariables().get("var").getFirst("a"));
assertEquals("d",result.getMatrixVariables().get("var").getFirst("c"));
result = matchAndExtract("/{*var}","/abc/123_456;a=b;c=d/789;a=e;f=g");
assertEquals("/abc/123_456/789",result.get("var").value());
assertEquals("[b, e]",result.get("var").parameters().get("a").toString());
assertEquals("[d]",result.get("var").parameters().get("c").toString());
assertEquals("[g]",result.get("var").parameters().get("f").toString());
assertEquals("/abc/123_456/789",result.getUriVariables().get("var"));
assertEquals("[b, e]",result.getMatrixVariables().get("var").get("a").toString());
assertEquals("d",result.getMatrixVariables().get("var").getFirst("c"));
assertEquals("g",result.getMatrixVariables().get("var").getFirst("f"));
result = matchAndExtract("/abc/{var}","/abc/one");
assertEquals("one",result.get("var").value());
assertEquals(0,result.get("var").parameters().size());
assertEquals("one",result.getUriVariables().get("var"));
assertNull(result.getMatrixVariables().get("var"));
}
// ---
private Map<String, PathMatchResult> matchAndExtract(String pattern, String path) {
private PathMatchResult matchAndExtract(String pattern, String path) {
return parse(pattern).matchAndExtract(PathPatternMatcherTests.toPathContainer(path));
}
@@ -1346,29 +1349,26 @@ public class PathPatternMatcherTests {
assertFalse(pattern.matches(PathContainer));
}
private Map<String, PathMatchResult> checkCapture(String uriTemplate, String path, String... keyValues) {
private PathMatchResult checkCapture(String uriTemplate, String path, String... keyValues) {
PathPatternParser parser = new PathPatternParser();
PathPattern pattern = parser.parse(uriTemplate);
Map<String, PathMatchResult> matchResults = pattern.matchAndExtract(toPathContainer(path));
PathMatchResult matchResult = pattern.matchAndExtract(toPathContainer(path));
Map<String, String> expectedKeyValues = new HashMap<>();
if (keyValues != null) {
for (int i = 0; i < keyValues.length; i += 2) {
expectedKeyValues.put(keyValues[i], keyValues[i + 1]);
}
for (int i = 0; i < keyValues.length; i += 2) {
expectedKeyValues.put(keyValues[i], keyValues[i + 1]);
}
Map<String, PathMatchResult> capturedVariables = matchResults;
for (Map.Entry<String, String> me : expectedKeyValues.entrySet()) {
String value = capturedVariables.get(me.getKey()).value();
String value = matchResult.getUriVariables().get(me.getKey());
if (value == null) {
fail("Did not find key '" + me.getKey() + "' in captured variables: "
+ capturedVariables);
+ matchResult.getUriVariables());
}
if (!value.equals(me.getValue())) {
fail("Expected value '" + me.getValue() + "' for key '" + me.getKey()
+ "' but was '" + value + "'");
}
}
return capturedVariables;
return matchResult;
}
private void checkExtractPathWithinPattern(String pattern, String path, String expected) {
@@ -1399,7 +1399,7 @@ public class PathPatternMatcherTests {
return pattern.getPathRemaining(toPathContainer(path));
}
private Map<String, PathMatchResult> matchAndExtract(PathPattern p, String path) {
private PathMatchResult matchAndExtract(PathPattern p, String path) {
return p.matchAndExtract(toPathContainer(path));
}

View File

@@ -19,14 +19,18 @@ package org.springframework.web.util.pattern;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
import org.springframework.web.util.pattern.PatternParseException.PatternMessage;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Exercise the {@link PathPatternParser}.
@@ -137,23 +141,23 @@ public class PathPatternParserTests {
pathPattern = checkStructure("/{var:[^\\/]*}");
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
Map<String, PathMatchResult> result = matchAndExtract(pathPattern,"/foo");
assertEquals("foo", result.get("var").value());
PathMatchResult result = matchAndExtract(pathPattern,"/foo");
assertEquals("foo", result.getUriVariables().get("var"));
pathPattern = checkStructure("/{var:\\[*}");
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
result = matchAndExtract(pathPattern,"/[[[");
assertEquals("[[[", result.get("var").value());
assertEquals("[[[", result.getUriVariables().get("var"));
pathPattern = checkStructure("/{var:[\\{]*}");
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
result = matchAndExtract(pathPattern,"/{{{");
assertEquals("{{{", result.get("var").value());
assertEquals("{{{", result.getUriVariables().get("var"));
pathPattern = checkStructure("/{var:[\\}]*}");
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
result = matchAndExtract(pathPattern,"/}}}");
assertEquals("}}}", result.get("var").value());
assertEquals("}}}", result.getUriVariables().get("var"));
pathPattern = checkStructure("*");
assertEquals(WildcardPathElement.class.getName(), pathPattern.getHeadSection().getClass().getName());
@@ -467,7 +471,7 @@ public class PathPatternParserTests {
assertFalse(pp.matches(PathPatternMatcherTests.toPathContainer(path)));
}
private Map<String, PathMatchResult> matchAndExtract(PathPattern pp, String path) {
private PathMatchResult matchAndExtract(PathPattern pp, String path) {
return pp.matchAndExtract(PathPatternMatcherTests.toPathContainer(path));
}