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);
}
}