Nullability fine-tuning (RequestContext, LocaleResolver)
Includes page-level JSTL time zone support for JSP tags. Issue: SPR-15720 Issue: SPR-15746
This commit is contained in:
@@ -175,9 +175,9 @@ class DefaultPathContainer implements PathContainer {
|
||||
return EMPTY_PATH;
|
||||
}
|
||||
|
||||
Assert.isTrue(fromIndex < toIndex, "fromIndex: " + fromIndex + " should be < toIndex " + toIndex);
|
||||
Assert.isTrue(fromIndex >= 0 && fromIndex < elements.size(), "Invalid fromIndex: " + fromIndex);
|
||||
Assert.isTrue(toIndex >= 0 && toIndex <= elements.size(), "Invalid toIndex: " + toIndex);
|
||||
Assert.isTrue(fromIndex < toIndex, () -> "fromIndex: " + fromIndex + " should be < toIndex " + toIndex);
|
||||
Assert.isTrue(fromIndex >= 0 && fromIndex < elements.size(), () -> "Invalid fromIndex: " + fromIndex);
|
||||
Assert.isTrue(toIndex >= 0 && toIndex <= elements.size(), () -> "Invalid toIndex: " + toIndex);
|
||||
|
||||
List<Element> subList = elements.subList(fromIndex, toIndex);
|
||||
String path = subList.stream().map(Element::value).collect(Collectors.joining(""));
|
||||
@@ -200,7 +200,7 @@ class DefaultPathContainer implements PathContainer {
|
||||
DefaultPathSegment(String value, String valueDecoded, String semicolonContent,
|
||||
MultiValueMap<String, String> params) {
|
||||
|
||||
Assert.isTrue(!value.contains("/"), "Invalid path segment value: " + value);
|
||||
Assert.isTrue(!value.contains("/"), () -> "Invalid path segment value: " + value);
|
||||
this.value = value;
|
||||
this.valueDecoded = valueDecoded;
|
||||
this.valueDecodedChars = valueDecoded.toCharArray();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
@@ -69,15 +70,16 @@ public interface PathContainer {
|
||||
* Return the original, raw (encoded) value for the path component.
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A path separator element.
|
||||
*/
|
||||
interface Separator extends Element {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A path segment element.
|
||||
*/
|
||||
@@ -104,7 +106,6 @@ public interface PathContainer {
|
||||
* Path parameters parsed from the path segment.
|
||||
*/
|
||||
MultiValueMap<String, String> parameters();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer.Element;
|
||||
import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
|
||||
/**
|
||||
* A path element representing capturing the rest of a path. In the pattern
|
||||
@@ -67,8 +66,8 @@ class CaptureTheRestPathElement extends PathElement {
|
||||
for (int i = pathIndex; i < matchingContext.pathLength; i++) {
|
||||
Element element = matchingContext.pathElements.get(i);
|
||||
if (element instanceof Segment) {
|
||||
MultiValueMap<String, String> parameters = ((Segment)element).parameters();
|
||||
if (parameters != null && parameters.size()!=0) {
|
||||
MultiValueMap<String, String> parameters = ((Segment) element).parameters();
|
||||
if (!parameters.isEmpty()) {
|
||||
if (parametersCollector == null) {
|
||||
parametersCollector = new LinkedMultiValueMap<>();
|
||||
}
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A path element representing capturing a piece of the path as a variable. In the pattern
|
||||
@@ -116,7 +114,7 @@ class CaptureVariablePathElement extends PathElement {
|
||||
if (matchingContext.isMatchStartMatching && pathIndex == matchingContext.pathLength) {
|
||||
match = true; // no more data but matches up to this point
|
||||
}
|
||||
else {
|
||||
else if (this.next != null) {
|
||||
match = this.next.matches(pathIndex, matchingContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.pattern.PatternParseException.PatternMessage;
|
||||
|
||||
/**
|
||||
@@ -117,11 +116,10 @@ class InternalPathPatternParser {
|
||||
* @throws PatternParseException in case of parse errors
|
||||
*/
|
||||
public PathPattern parse(String pathPattern) throws PatternParseException {
|
||||
if (pathPattern == null) {
|
||||
pathPattern = "";
|
||||
}
|
||||
Assert.notNull(pathPattern, "Path pattern must not be null");
|
||||
|
||||
this.pathPatternData = pathPattern.toCharArray();
|
||||
this.pathPatternLength = pathPatternData.length;
|
||||
this.pathPatternLength = this.pathPatternData.length;
|
||||
this.headPE = null;
|
||||
this.currentPE = null;
|
||||
this.capturedVariableNames = null;
|
||||
|
||||
@@ -34,6 +34,7 @@ class LiteralPathElement extends PathElement {
|
||||
|
||||
private boolean caseSensitive;
|
||||
|
||||
|
||||
public LiteralPathElement(int pos, char[] literalText, boolean caseSensitive, char separator) {
|
||||
super(pos, separator);
|
||||
this.len = literalText.length;
|
||||
@@ -50,6 +51,7 @@ class LiteralPathElement extends PathElement {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(int pathIndex, MatchingContext matchingContext) {
|
||||
if (pathIndex >= matchingContext.pathLength) {
|
||||
@@ -104,22 +106,22 @@ class LiteralPathElement extends PathElement {
|
||||
if (matchingContext.isMatchStartMatching && pathIndex == matchingContext.pathLength) {
|
||||
return true; // no more data but everything matched so far
|
||||
}
|
||||
return this.next.matches(pathIndex, matchingContext);
|
||||
return (this.next != null && this.next.matches(pathIndex, matchingContext));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNormalizedLength() {
|
||||
return len;
|
||||
return this.len;
|
||||
}
|
||||
|
||||
public char[] getChars() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return "Literal(" + String.valueOf(this.text) + ")";
|
||||
}
|
||||
|
||||
public char[] getChars() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
|
||||
/**
|
||||
* A regex path element. Used to represent any complicated element of the path.
|
||||
@@ -36,9 +35,9 @@ import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
*/
|
||||
class RegexPathElement extends PathElement {
|
||||
|
||||
private final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}");
|
||||
private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}");
|
||||
|
||||
private final String DEFAULT_VARIABLE_PATTERN = "(.*)";
|
||||
private static final String DEFAULT_VARIABLE_PATTERN = "(.*)";
|
||||
|
||||
|
||||
private char[] regex;
|
||||
@@ -145,9 +144,9 @@ class RegexPathElement extends PathElement {
|
||||
// No more pattern, is there more data?
|
||||
// If pattern is capturing variables there must be some actual data to bind to them
|
||||
matches = (pathIndex + 1) >= matchingContext.pathLength &&
|
||||
((this.variableNames.size() == 0) ? true : textToMatch.length() > 0);
|
||||
(this.variableNames.isEmpty() || textToMatch.length() > 0);
|
||||
if (!matches && matchingContext.isAllowOptionalTrailingSlash()) {
|
||||
matches = ((this.variableNames.size() == 0) ? true : textToMatch.length() > 0) &&
|
||||
matches = (this.variableNames.isEmpty() || textToMatch.length() > 0) &&
|
||||
(pathIndex + 2) >= matchingContext.pathLength &&
|
||||
matchingContext.isSeparator(pathIndex + 1);
|
||||
}
|
||||
@@ -155,9 +154,9 @@ class RegexPathElement extends PathElement {
|
||||
}
|
||||
else {
|
||||
if (matchingContext.isMatchStartMatching && (pathIndex + 1 >= matchingContext.pathLength)) {
|
||||
return true; // no more data but matches up to this point
|
||||
return true; // no more data but matches up to this point
|
||||
}
|
||||
matches = this.next.matches(pathIndex + 1, matchingContext);
|
||||
matches = (this.next != null && this.next.matches(pathIndex + 1, matchingContext));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ class SeparatorPathElement extends PathElement {
|
||||
else {
|
||||
pathIndex++;
|
||||
if (matchingContext.isMatchStartMatching && pathIndex == matchingContext.pathLength) {
|
||||
return true; // no more data but matches up to this point
|
||||
return true; // no more data but matches up to this point
|
||||
}
|
||||
return this.next.matches(pathIndex, matchingContext);
|
||||
return (this.next != null && this.next.matches(pathIndex, matchingContext));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -114,7 +114,7 @@ class SingleCharWildcardedPathElement extends PathElement {
|
||||
if (matchingContext.isMatchStartMatching && pathIndex == matchingContext.pathLength) {
|
||||
return true; // no more data but everything matched so far
|
||||
}
|
||||
return this.next.matches(pathIndex, matchingContext);
|
||||
return (this.next != null && this.next.matches(pathIndex, matchingContext));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
import org.springframework.http.server.reactive.PathContainer.Element;
|
||||
import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
import org.springframework.web.util.pattern.PathPattern.MatchingContext;
|
||||
|
||||
/**
|
||||
* A wildcard path element. In the pattern '/foo/*/goo' the * is
|
||||
@@ -80,7 +80,7 @@ class WildcardPathElement extends PathElement {
|
||||
if (segmentData == null || segmentData.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
return this.next.matches(pathIndex, matchingContext);
|
||||
return (this.next != null && this.next.matches(pathIndex, matchingContext));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathRemainingMatchInfo;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
@@ -48,6 +48,7 @@ public class PathPatternMatcherTests {
|
||||
|
||||
private char separator = PathPatternParser.DEFAULT_SEPARATOR;
|
||||
|
||||
|
||||
@Test
|
||||
public void pathContainer() {
|
||||
assertEquals("[/][abc][/][def]",elementsToString(toPathContainer("/abc/def").elements()));
|
||||
@@ -1044,16 +1045,15 @@ public class PathPatternMatcherTests {
|
||||
assertEquals("/*.html", pathMatcher.combine("/**", "/*.html"));
|
||||
assertEquals("/*.html", pathMatcher.combine("/*", "/*.html"));
|
||||
assertEquals("/*.html", pathMatcher.combine("/*.*", "/*.html"));
|
||||
assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
|
||||
assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
|
||||
assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
|
||||
assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
|
||||
assertEquals("/{foo:.*[^0-9].*}/edit/",
|
||||
pathMatcher.combine("/{foo:.*[^0-9].*}", "/edit/")); // SPR-10062
|
||||
pathMatcher.combine("/{foo:.*[^0-9].*}", "/edit/")); // SPR-10062
|
||||
assertEquals("/1.0/foo/test", pathMatcher.combine("/1.0", "/foo/test"));
|
||||
// SPR-10554
|
||||
assertEquals("/hotel", pathMatcher.combine("/", "/hotel")); // SPR-12975
|
||||
assertEquals("/hotel/booking", pathMatcher.combine("/hotel/", "/booking")); // SPR-12975
|
||||
assertEquals("/hotel", pathMatcher.combine("/", "/hotel")); // SPR-12975
|
||||
assertEquals("/hotel/booking", pathMatcher.combine("/hotel/", "/booking")); // SPR-12975
|
||||
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?
|
||||
}
|
||||
@@ -1254,7 +1254,7 @@ public class PathPatternMatcherTests {
|
||||
paths.clear();
|
||||
}
|
||||
|
||||
@Test // SPR-13286
|
||||
@Test // SPR-13286
|
||||
public void caseInsensitive() {
|
||||
PathPatternParser pp = new PathPatternParser();
|
||||
pp.setCaseSensitive(false);
|
||||
@@ -1264,7 +1264,6 @@ public class PathPatternMatcherTests {
|
||||
assertMatches(p,"/group/Sales/members");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void parameters() {
|
||||
// CaptureVariablePathElement
|
||||
@@ -1297,7 +1296,6 @@ public class PathPatternMatcherTests {
|
||||
assertNull(result.getMatrixVariables().get("var"));
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private PathMatchResult matchAndExtract(String pattern, String path) {
|
||||
return parse(pattern).matchAndExtract(PathPatternMatcherTests.toPathContainer(path));
|
||||
@@ -1374,19 +1372,6 @@ public class PathPatternMatcherTests {
|
||||
assertEquals(expected, s);
|
||||
}
|
||||
|
||||
|
||||
static class TestPathCombiner {
|
||||
|
||||
PathPatternParser pp = new PathPatternParser();
|
||||
|
||||
public String combine(String string1, String string2) {
|
||||
PathPattern pattern1 = pp.parse(string1);
|
||||
PathPattern pattern2 = pp.parse(string2);
|
||||
return pattern1.combine(pattern2).getPatternString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private PathRemainingMatchInfo getPathRemaining(String pattern, String path) {
|
||||
return parse(pattern).getPathRemaining(toPathContainer(path));
|
||||
}
|
||||
@@ -1407,4 +1392,17 @@ public class PathPatternMatcherTests {
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
|
||||
static class TestPathCombiner {
|
||||
|
||||
PathPatternParser pp = new PathPatternParser();
|
||||
|
||||
public String combine(String string1, String string2) {
|
||||
PathPattern pattern1 = pp.parse(string1);
|
||||
PathPattern pattern2 = pp.parse(string2);
|
||||
return pattern1.combine(pattern2).getPatternString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user