diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java index 216053e7708..709dcaf2932 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java @@ -50,9 +50,6 @@ class WiretapConnector implements ClientHttpConnector { this.delegate = delegate; } - public ClientHttpConnector getDelegate() { - return this.delegate; - } @Override public Mono connect(HttpMethod method, URI uri, @@ -69,7 +66,7 @@ class WiretapConnector implements ClientHttpConnector { .map(response -> { WiretapClientHttpRequest wrappedRequest = requestRef.get(); String requestId = wrappedRequest.getHeaders().getFirst(WebTestClient.WEBTESTCLIENT_REQUEST_ID); - Assert.notNull(requestId, "No \"" + WebTestClient.WEBTESTCLIENT_REQUEST_ID + "\" header"); + Assert.state(requestId != null, () -> "No \"" + WebTestClient.WEBTESTCLIENT_REQUEST_ID + "\" header"); WiretapClientHttpResponse wrappedResponse = new WiretapClientHttpResponse(response); ExchangeResult result = new ExchangeResult(wrappedRequest, wrappedResponse); this.exchanges.put(requestId, result); @@ -82,7 +79,7 @@ class WiretapConnector implements ClientHttpConnector { */ public ExchangeResult claimRequest(String requestId) { ExchangeResult result = this.exchanges.remove(requestId); - Assert.notNull(result, "No match for " + WebTestClient.WEBTESTCLIENT_REQUEST_ID + "=" + requestId); + Assert.state(result != null, () -> "No match for " + WebTestClient.WEBTESTCLIENT_REQUEST_ID + "=" + requestId); return result; } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultPathContainer.java b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultPathContainer.java index 726a3e685f2..bc9b6748025 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultPathContainer.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultPathContainer.java @@ -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 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 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(); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java b/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java index ee8492822f1..795ef4434f2 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/PathContainer.java @@ -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 parameters(); - } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureTheRestPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureTheRestPathElement.java index 13df50e691d..30a73ec6bb6 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureTheRestPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureTheRestPathElement.java @@ -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 parameters = ((Segment)element).parameters(); - if (parameters != null && parameters.size()!=0) { + MultiValueMap parameters = ((Segment) element).parameters(); + if (!parameters.isEmpty()) { if (parametersCollector == null) { parametersCollector = new LinkedMultiValueMap<>(); } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java index f5c3051618c..018fda6dcf0 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java @@ -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); } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java b/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java index 6aa6ef67d73..3ec91daa8f8 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java @@ -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; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java index 4d485a6107e..0a33534061f 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java @@ -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; - } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java index f75fbc1e376..63de7014fff 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java @@ -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; /** diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/RegexPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/RegexPathElement.java index 0ae3fdfb8f2..d7743339ffe 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/RegexPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/RegexPathElement.java @@ -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)); } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java index cd0cfa66c5f..8290a89d0d5 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java @@ -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; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java index bf1618d7ff6..95c6f58125d 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java @@ -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)); } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/WildcardPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/WildcardPathElement.java index 85e6a699ba1..b3bf34b6a74 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/WildcardPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/WildcardPathElement.java @@ -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)); } } diff --git a/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternMatcherTests.java b/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternMatcherTests.java index 3ace116f64b..36e9d8a395e 100644 --- a/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternMatcherTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternMatcherTests.java @@ -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(); + } + + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleContextResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleContextResolver.java index ed86f27bd3e..48d8c6b55dd 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleContextResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleContextResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 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. @@ -17,7 +17,6 @@ package org.springframework.web.servlet; import java.util.Locale; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -70,6 +69,7 @@ public interface LocaleContextResolver extends LocaleResolver { * @see org.springframework.context.i18n.SimpleLocaleContext * @see org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext */ - void setLocaleContext(HttpServletRequest request, HttpServletResponse response, @Nullable LocaleContext localeContext); + void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response, + @Nullable LocaleContext localeContext); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleResolver.java index b7710b40f33..eb9c16527bf 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/LocaleResolver.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. @@ -17,7 +17,6 @@ package org.springframework.web.servlet; import java.util.Locale; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -69,6 +68,6 @@ public interface LocaleResolver { * @throws UnsupportedOperationException if the LocaleResolver * implementation does not support dynamic changing of the locale */ - void setLocale(HttpServletRequest request, HttpServletResponse response, @Nullable Locale locale); + void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ThemeResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ThemeResolver.java index fd4b6b7fb10..a59024c3793 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ThemeResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ThemeResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 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. @@ -64,6 +64,6 @@ public interface ThemeResolver { * @throws UnsupportedOperationException if the ThemeResolver implementation * does not support dynamic changing of the theme */ - void setThemeName(HttpServletRequest request, HttpServletResponse response, @Nullable String themeName); + void setThemeName(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/CookieLocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/CookieLocaleResolver.java index 7978eddf14e..0bb48c92484 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/CookieLocaleResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/CookieLocaleResolver.java @@ -26,6 +26,7 @@ import org.springframework.context.i18n.LocaleContext; import org.springframework.context.i18n.SimpleLocaleContext; import org.springframework.context.i18n.TimeZoneAwareLocaleContext; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.servlet.LocaleContextResolver; import org.springframework.web.servlet.LocaleResolver; @@ -84,8 +85,10 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte private boolean languageTagCompliant = false; + @Nullable private Locale defaultLocale; + @Nullable private TimeZone defaultTimeZone; @@ -224,12 +227,16 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte } @Override - public void setLocale(HttpServletRequest request, HttpServletResponse response, @Nullable Locale locale) { + public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) { setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null)); } @Override - public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, @Nullable LocaleContext localeContext) { + public void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response, + @Nullable LocaleContext localeContext) { + + Assert.notNull(response, "HttpServletResponse is required for CookieLocaleResolver"); + Locale locale = null; TimeZone timeZone = null; if (localeContext != null) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/FixedLocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/FixedLocaleResolver.java index f9778a113fe..6596c50ccd2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/FixedLocaleResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/FixedLocaleResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 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. @@ -93,7 +93,9 @@ public class FixedLocaleResolver extends AbstractLocaleContextResolver { } @Override - public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, @Nullable LocaleContext localeContext) { + public void setLocaleContext( HttpServletRequest request, @Nullable HttpServletResponse response, + @Nullable LocaleContext localeContext) { + throw new UnsupportedOperationException("Cannot change fixed locale - use a different locale resolution strategy"); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/SessionLocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/SessionLocaleResolver.java index 345647181c2..0a4516cf537 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/SessionLocaleResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/SessionLocaleResolver.java @@ -18,7 +18,6 @@ package org.springframework.web.servlet.i18n; import java.util.Locale; import java.util.TimeZone; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -139,7 +138,9 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver { } @Override - public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, @Nullable LocaleContext localeContext) { + public void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response, + @Nullable LocaleContext localeContext) { + Locale locale = null; TimeZone timeZone = null; if (localeContext != null) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java index bce5e8df68a..7dce89a0962 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java @@ -93,9 +93,7 @@ public class BindStatus { * @param htmlEscape whether to HTML-escape error messages and string values * @throws IllegalStateException if no corresponding Errors object found */ - public BindStatus(RequestContext requestContext, String path, boolean htmlEscape) - throws IllegalStateException { - + public BindStatus(RequestContext requestContext, String path, boolean htmlEscape) throws IllegalStateException { this.requestContext = requestContext; this.path = path; this.htmlEscape = htmlEscape; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/JspAwareRequestContext.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/JspAwareRequestContext.java index 4384f6d626a..cde408624a2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/JspAwareRequestContext.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/JspAwareRequestContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 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. @@ -18,7 +18,7 @@ package org.springframework.web.servlet.support; import java.util.Locale; import java.util.Map; - +import java.util.TimeZone; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; @@ -48,7 +48,7 @@ public class JspAwareRequestContext extends RequestContext { * @param pageContext current JSP page context */ public JspAwareRequestContext(PageContext pageContext) { - initContext(pageContext, null); + this(pageContext, null); } /** @@ -59,23 +59,9 @@ public class JspAwareRequestContext extends RequestContext { * (can be {@code null}, using the request attributes for Errors retrieval) */ public JspAwareRequestContext(PageContext pageContext, @Nullable Map model) { - initContext(pageContext, model); - } - - /** - * Initialize this context with the given page context, - * using the given model attributes for Errors retrieval. - * @param pageContext current JSP page context - * @param model the model attributes for the current view - * (can be {@code null}, using the request attributes for Errors retrieval) - */ - protected void initContext(PageContext pageContext, @Nullable Map model) { - if (!(pageContext.getRequest() instanceof HttpServletRequest)) { - throw new IllegalArgumentException("RequestContext only supports HTTP requests"); - } - this.pageContext = pageContext; - initContext((HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse(), + super((HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse(), pageContext.getServletContext(), model); + this.pageContext = pageContext; } @@ -88,9 +74,9 @@ public class JspAwareRequestContext extends RequestContext { } /** - * This implementation checks for a JSTL locale attribute - * in page, request, session or application scope; if not found, - * returns the {@code HttpServletRequest.getLocale()}. + * This implementation checks for a JSTL locale attribute in page, + * request, session or application scope; if not found, returns the + * {@code HttpServletRequest.getLocale()}. */ @Override protected Locale getFallbackLocale() { @@ -103,6 +89,21 @@ public class JspAwareRequestContext extends RequestContext { return getRequest().getLocale(); } + /** + * This implementation checks for a JSTL time zone attribute in page, + * request, session or application scope; if not found, returns {@code null}. + */ + @Override + protected TimeZone getFallbackTimeZone() { + if (jstlPresent) { + TimeZone timeZone = JstlPageLocaleResolver.getJstlTimeZone(getPageContext()); + if (timeZone != null) { + return timeZone; + } + } + return null; + } + /** * Inner class that isolates the JSTL dependency. @@ -114,6 +115,11 @@ public class JspAwareRequestContext extends RequestContext { Object localeObject = Config.find(pageContext, Config.FMT_LOCALE); return (localeObject instanceof Locale ? (Locale) localeObject : null); } + + public static TimeZone getJstlTimeZone(PageContext pageContext) { + Object timeZoneObject = Config.find(pageContext, Config.FMT_TIME_ZONE); + return (timeZoneObject instanceof TimeZone ? (TimeZone) timeZoneObject : null); + } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java index f38222c6804..4ddfabc81a7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java @@ -73,7 +73,6 @@ import org.springframework.web.util.WebUtils; * @see org.springframework.web.servlet.DispatcherServlet * @see org.springframework.web.servlet.view.AbstractView#setRequestContextAttribute * @see org.springframework.web.servlet.view.UrlBasedViewResolver#setRequestContextAttribute - * @see #getFallbackLocale() */ public class RequestContext { @@ -95,7 +94,6 @@ public class RequestContext { protected static final boolean jstlPresent = ClassUtils.isPresent( "javax.servlet.jsp.jstl.core.Config", RequestContext.class.getClassLoader()); - @Nullable private HttpServletRequest request; @Nullable @@ -104,7 +102,6 @@ public class RequestContext { @Nullable private Map model; - @Nullable private WebApplicationContext webApplicationContext; @Nullable @@ -122,7 +119,6 @@ public class RequestContext { @Nullable private Boolean responseEncodedHtmlEscape; - @Nullable private UrlPathHelper urlPathHelper; @Nullable @@ -143,7 +139,7 @@ public class RequestContext { * @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.ServletContext) */ public RequestContext(HttpServletRequest request) { - initContext(request, null, null, null); + this(request, null, null, null); } /** @@ -158,7 +154,7 @@ public class RequestContext { * @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, Map) */ public RequestContext(HttpServletRequest request, HttpServletResponse response) { - initContext(request, response, null, null); + this(request, response, null, null); } /** @@ -174,7 +170,7 @@ public class RequestContext { * @see org.springframework.web.servlet.DispatcherServlet */ public RequestContext(HttpServletRequest request, @Nullable ServletContext servletContext) { - initContext(request, null, servletContext, null); + this(request, null, servletContext, null); } /** @@ -189,7 +185,7 @@ public class RequestContext { * @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, Map) */ public RequestContext(HttpServletRequest request, @Nullable Map model) { - initContext(request, null, null, model); + this(request, null, null, model); } /** @@ -206,34 +202,7 @@ public class RequestContext { * @see org.springframework.web.context.WebApplicationContext * @see org.springframework.web.servlet.DispatcherServlet */ - public RequestContext(HttpServletRequest request, HttpServletResponse response, @Nullable ServletContext servletContext, - @Nullable Map model) { - - initContext(request, response, servletContext, model); - } - - /** - * Default constructor for subclasses. - */ - protected RequestContext() { - } - - - /** - * Initialize this context with the given request, using the given model attributes for Errors retrieval. - *

Delegates to {@code getFallbackLocale} and {@code getFallbackTheme} for determining the fallback - * locale and theme, respectively, if no LocaleResolver and/or ThemeResolver can be found in the request. - * @param request current HTTP request - * @param servletContext the servlet context of the web application (can be {@code null}; necessary for - * fallback to root WebApplicationContext) - * @param model the model attributes for the current view (can be {@code null}, using the request - * attributes for Errors retrieval) - * @see #getFallbackLocale - * @see #getFallbackTheme - * @see org.springframework.web.servlet.DispatcherServlet#LOCALE_RESOLVER_ATTRIBUTE - * @see org.springframework.web.servlet.DispatcherServlet#THEME_RESOLVER_ATTRIBUTE - */ - protected void initContext(HttpServletRequest request, @Nullable HttpServletResponse response, + public RequestContext(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable ServletContext servletContext, @Nullable Map model) { this.request = request; @@ -242,36 +211,35 @@ public class RequestContext { // Fetch WebApplicationContext, either from DispatcherServlet or the root context. // ServletContext needs to be specified to be able to fall back to the root context! - this.webApplicationContext = (WebApplicationContext) request.getAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE); - if (this.webApplicationContext == null) { - this.webApplicationContext = RequestContextUtils.findWebApplicationContext(request, servletContext); - if (this.webApplicationContext == null) { + WebApplicationContext wac = (WebApplicationContext) request.getAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE); + if (wac == null) { + wac = RequestContextUtils.findWebApplicationContext(request, servletContext); + if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: not in a DispatcherServlet " + "request and no ContextLoaderListener registered?"); } } + this.webApplicationContext = wac; + + Locale locale = null; + TimeZone timeZone = null; // Determine locale to use for this RequestContext. LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); if (localeResolver instanceof LocaleContextResolver) { LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request); - this.locale = localeContext.getLocale(); + locale = localeContext.getLocale(); if (localeContext instanceof TimeZoneAwareLocaleContext) { - this.timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone(); + timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone(); } } else if (localeResolver != null) { // Try LocaleResolver (we're within a DispatcherServlet request). - this.locale = localeResolver.resolveLocale(request); + locale = localeResolver.resolveLocale(request); } - // Try JSTL fallbacks if necessary. - if (this.locale == null) { - this.locale = getFallbackLocale(); - } - if (this.timeZone == null) { - this.timeZone = getFallbackTimeZone(); - } + this.locale = locale; + this.timeZone = timeZone; // Determine default HTML escape setting from the "defaultHtmlEscape" // context-param in web.xml, if any. @@ -290,57 +258,6 @@ public class RequestContext { } } - /** - * Determine the fallback locale for this context. - *

The default implementation checks for a JSTL locale attribute in request, session - * or application scope; if not found, returns the {@code HttpServletRequest.getLocale()}. - * @return the fallback locale (never {@code null}) - * @see javax.servlet.http.HttpServletRequest#getLocale() - */ - protected Locale getFallbackLocale() { - if (jstlPresent) { - Locale locale = JstlLocaleResolver.getJstlLocale(getRequest(), getServletContext()); - if (locale != null) { - return locale; - } - } - return getRequest().getLocale(); - } - - /** - * Determine the fallback time zone for this context. - *

The default implementation checks for a JSTL time zone attribute in request, - * session or application scope; returns {@code null} if not found. - * @return the fallback time zone (or {@code null} if none derivable from the request) - */ - @Nullable - protected TimeZone getFallbackTimeZone() { - if (jstlPresent) { - TimeZone timeZone = JstlLocaleResolver.getJstlTimeZone(getRequest(), getServletContext()); - if (timeZone != null) { - return timeZone; - } - } - return null; - } - - /** - * Determine the fallback theme for this context. - *

The default implementation returns the default theme (with name "theme"). - * @return the fallback theme (never {@code null}) - */ - protected Theme getFallbackTheme() { - ThemeSource themeSource = RequestContextUtils.getThemeSource(getRequest()); - if (themeSource == null) { - themeSource = new ResourceBundleThemeSource(); - } - Theme theme = themeSource.getTheme(DEFAULT_THEME_NAME); - if (theme == null) { - throw new IllegalStateException("No theme defined and no fallback theme found"); - } - return theme; - } - /** * Return the underlying HttpServletRequest. Only intended for cooperating classes in this package. @@ -387,7 +304,7 @@ public class RequestContext { * @see RequestContextUtils#getLocale */ public final Locale getLocale() { - return this.locale; + return (this.locale != null ? this.locale : getFallbackLocale()); } /** @@ -398,7 +315,41 @@ public class RequestContext { */ @Nullable public TimeZone getTimeZone() { - return this.timeZone; + return (this.timeZone != null ? this.timeZone : getFallbackTimeZone()); + } + + /** + * Determine the fallback locale for this context. + *

The default implementation checks for a JSTL locale attribute in request, session + * or application scope; if not found, returns the {@code HttpServletRequest.getLocale()}. + * @return the fallback locale (never {@code null}) + * @see javax.servlet.http.HttpServletRequest#getLocale() + */ + protected Locale getFallbackLocale() { + if (jstlPresent) { + Locale locale = JstlLocaleResolver.getJstlLocale(getRequest(), getServletContext()); + if (locale != null) { + return locale; + } + } + return getRequest().getLocale(); + } + + /** + * Determine the fallback time zone for this context. + *

The default implementation checks for a JSTL time zone attribute in request, + * session or application scope; returns {@code null} if not found. + * @return the fallback time zone (or {@code null} if none derivable from the request) + */ + @Nullable + protected TimeZone getFallbackTimeZone() { + if (jstlPresent) { + TimeZone timeZone = JstlLocaleResolver.getJstlTimeZone(getRequest(), getServletContext()); + if (timeZone != null) { + return timeZone; + } + } + return null; } /** @@ -452,6 +403,23 @@ public class RequestContext { return this.theme; } + /** + * Determine the fallback theme for this context. + *

The default implementation returns the default theme (with name "theme"). + * @return the fallback theme (never {@code null}) + */ + protected Theme getFallbackTheme() { + ThemeSource themeSource = RequestContextUtils.getThemeSource(getRequest()); + if (themeSource == null) { + themeSource = new ResourceBundleThemeSource(); + } + Theme theme = themeSource.getTheme(DEFAULT_THEME_NAME); + if (theme == null) { + throw new IllegalStateException("No theme defined and no fallback theme found"); + } + return theme; + } + /** * Change the current theme to the specified one, * storing the new theme name through the configured {@link ThemeResolver}. @@ -524,6 +492,7 @@ public class RequestContext { * @return whether default use of response encoding HTML escaping is enabled (null = no explicit default) * @since 4.1.2 */ + @Nullable public Boolean getResponseEncodedHtmlEscape() { return this.responseEncodedHtmlEscape; } @@ -683,7 +652,7 @@ public class RequestContext { * @return the message */ public String getMessage(String code, @Nullable Object[] args, String defaultMessage, boolean htmlEscape) { - String msg = this.webApplicationContext.getMessage(code, args, defaultMessage, this.locale); + String msg = this.webApplicationContext.getMessage(code, args, defaultMessage, getLocale()); return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg); } @@ -728,7 +697,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getMessage(String code, @Nullable Object[] args, boolean htmlEscape) throws NoSuchMessageException { - String msg = this.webApplicationContext.getMessage(code, args, this.locale); + String msg = this.webApplicationContext.getMessage(code, args, getLocale()); return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg); } @@ -750,7 +719,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getMessage(MessageSourceResolvable resolvable, boolean htmlEscape) throws NoSuchMessageException { - String msg = this.webApplicationContext.getMessage(resolvable, this.locale); + String msg = this.webApplicationContext.getMessage(resolvable, getLocale()); return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg); } @@ -763,7 +732,7 @@ public class RequestContext { * @return the message */ public String getThemeMessage(String code, String defaultMessage) { - return getTheme().getMessageSource().getMessage(code, null, defaultMessage, this.locale); + return getTheme().getMessageSource().getMessage(code, null, defaultMessage, getLocale()); } /** @@ -776,7 +745,7 @@ public class RequestContext { * @return the message */ public String getThemeMessage(String code, @Nullable Object[] args, String defaultMessage) { - return getTheme().getMessageSource().getMessage(code, args, defaultMessage, this.locale); + return getTheme().getMessageSource().getMessage(code, args, defaultMessage, getLocale()); } /** @@ -790,7 +759,7 @@ public class RequestContext { */ public String getThemeMessage(String code, @Nullable List args, String defaultMessage) { return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), - defaultMessage, this.locale); + defaultMessage, getLocale()); } /** @@ -802,7 +771,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getThemeMessage(String code) throws NoSuchMessageException { - return getTheme().getMessageSource().getMessage(code, null, this.locale); + return getTheme().getMessageSource().getMessage(code, null, getLocale()); } /** @@ -815,7 +784,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getThemeMessage(String code, @Nullable Object[] args) throws NoSuchMessageException { - return getTheme().getMessageSource().getMessage(code, args, this.locale); + return getTheme().getMessageSource().getMessage(code, args, getLocale()); } /** @@ -828,7 +797,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getThemeMessage(String code, @Nullable List args) throws NoSuchMessageException { - return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), this.locale); + return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), getLocale()); } /** @@ -840,7 +809,7 @@ public class RequestContext { * @throws org.springframework.context.NoSuchMessageException if not found */ public String getThemeMessage(MessageSourceResolvable resolvable) throws NoSuchMessageException { - return getTheme().getMessageSource().getMessage(resolvable, this.locale); + return getTheme().getMessageSource().getMessage(resolvable, getLocale()); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/CookieThemeResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/CookieThemeResolver.java index 0cdd92aceb3..77f3bb4cb37 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/CookieThemeResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/CookieThemeResolver.java @@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.util.CookieGenerator; @@ -104,7 +105,11 @@ public class CookieThemeResolver extends CookieGenerator implements ThemeResolve } @Override - public void setThemeName(HttpServletRequest request, HttpServletResponse response, @Nullable String themeName) { + public void setThemeName( + HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) { + + Assert.notNull(response, "HttpServletResponse is required for CookieThemeResolver"); + if (StringUtils.hasText(themeName)) { // Set request attribute and add cookie. request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, themeName); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/FixedThemeResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/FixedThemeResolver.java index dd34efbf89e..c45c624646a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/FixedThemeResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/FixedThemeResolver.java @@ -42,7 +42,9 @@ public class FixedThemeResolver extends AbstractThemeResolver { } @Override - public void setThemeName(HttpServletRequest request, HttpServletResponse response, @Nullable String themeName) { + public void setThemeName( + HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) { + throw new UnsupportedOperationException("Cannot change theme - use a different theme resolution strategy"); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/SessionThemeResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/SessionThemeResolver.java index bb8c3a3075d..1b7f0c083ff 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/SessionThemeResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/theme/SessionThemeResolver.java @@ -58,7 +58,9 @@ public class SessionThemeResolver extends AbstractThemeResolver { } @Override - public void setThemeName(HttpServletRequest request, HttpServletResponse response, @Nullable String themeName) { + public void setThemeName( + HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) { + WebUtils.setSessionAttribute(request, THEME_SESSION_ATTRIBUTE_NAME, (StringUtils.hasText(themeName) ? themeName : null)); }