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:
Juergen Hoeller
2017-07-07 18:46:19 +02:00
parent 4a3ca17d3f
commit 00f4c36d7a
25 changed files with 207 additions and 227 deletions

View File

@@ -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();

View File

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

View File

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

View File

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

View File

@@ -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;

View File

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

View File

@@ -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;
/**

View File

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

View File

@@ -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;

View File

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

View File

@@ -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/&ast;/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));
}
}

View File

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