Simplify default locale/timezone resolution in cookie/session locale resolvers

At present, the customization of the default locale and timezone
resolution in CookieLocaleResolver and SessionLocaleResolver requires
subclassing them and overriding determineDefaultLocale and/or
determineDefaultTimeZone methods.

This commit simplifies resolution of the default locale and timezone
resolution by introducing dedicated functions for these purposes, thus
allowing customization without needing to resort to subclassing the
locale resolvers.

Closes gh-27609
This commit is contained in:
Vedran Pavic
2021-10-26 00:31:56 +02:00
committed by Sam Brannen
parent 94cc2da33b
commit 864dcf67d8
4 changed files with 146 additions and 21 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.web.servlet.i18n;
import java.util.Locale;
import java.util.TimeZone;
import java.util.function.Function;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
@@ -50,6 +51,7 @@ import org.springframework.web.util.WebUtils;
*
* @author Juergen Hoeller
* @author Jean-Pierre Pawlak
* @author Vedran Pavic
* @since 27.02.2003
* @see #setDefaultLocale
* @see #setDefaultTimeZone
@@ -94,6 +96,15 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
@Nullable
private TimeZone defaultTimeZone;
private Function<HttpServletRequest, Locale> defaultLocaleFunction = request -> {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
};
private Function<HttpServletRequest, TimeZone> defaultTimeZoneFunction = request -> getDefaultTimeZone();
/**
* Create a new instance of {@link CookieLocaleResolver} using the
@@ -137,8 +148,8 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
* @since 5.1.7
* @see #setDefaultLocale
* @see #setDefaultTimeZone
* @see #determineDefaultLocale
* @see #determineDefaultTimeZone
* @see #setDefaultLocaleFunction(Function)
* @see #setDefaultTimeZoneFunction(Function)
*/
public void setRejectInvalidCookies(boolean rejectInvalidCookies) {
this.rejectInvalidCookies = rejectInvalidCookies;
@@ -186,6 +197,35 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
return this.defaultTimeZone;
}
/**
* Set the function used to determine the default locale for the given request,
* called if no {@link Locale} session attribute has been found.
* <p>The default implementation returns the specified default locale,
* if any, else falls back to the request's accept-header locale.
* @param defaultLocaleFunction the function used to determine the default locale
* @since 6.0
* @see #setDefaultLocale
* @see jakarta.servlet.http.HttpServletRequest#getLocale()
*/
public void setDefaultLocaleFunction(Function<HttpServletRequest, Locale> defaultLocaleFunction) {
Assert.notNull(defaultLocaleFunction, "defaultLocaleFunction must not be null");
this.defaultLocaleFunction = defaultLocaleFunction;
}
/**
* Set the function used to determine the default time zone for the given request,
* called if no {@link TimeZone} session attribute has been found.
* <p>The default implementation returns the specified default time zone,
* if any, or {@code null} otherwise.
* @param defaultTimeZoneFunction the function used to determine the default time zone
* @since 6.0
* @see #setDefaultTimeZone
*/
public void setDefaultTimeZoneFunction(Function<HttpServletRequest, TimeZone> defaultTimeZoneFunction) {
Assert.notNull(defaultTimeZoneFunction, "defaultTimeZoneFunction must not be null");
this.defaultTimeZoneFunction = defaultTimeZoneFunction;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
@@ -260,9 +300,9 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
}
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
(locale != null ? locale : determineDefaultLocale(request)));
(locale != null ? locale : this.defaultLocaleFunction.apply(request)));
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
(timeZone != null ? timeZone : this.defaultTimeZoneFunction.apply(request)));
}
}
@@ -291,9 +331,9 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
removeCookie(response);
}
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
(locale != null ? locale : determineDefaultLocale(request)));
(locale != null ? locale : this.defaultLocaleFunction.apply(request)));
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
(timeZone != null ? timeZone : this.defaultTimeZoneFunction.apply(request)));
}
@@ -335,13 +375,11 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
* @return the default locale (never {@code null})
* @see #setDefaultLocale
* @see jakarta.servlet.http.HttpServletRequest#getLocale()
* @deprecated as of 6.0, in favor of {@link #setDefaultLocaleFunction(Function)}
*/
@Deprecated
protected Locale determineDefaultLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
return this.defaultLocaleFunction.apply(request);
}
/**
@@ -352,10 +390,12 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
* @param request the request to resolve the time zone for
* @return the default time zone (or {@code null} if none defined)
* @see #setDefaultTimeZone
* @deprecated as of 6.0, in favor of {@link #setDefaultTimeZoneFunction(Function)}
*/
@Deprecated
@Nullable
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
return getDefaultTimeZone();
return this.defaultTimeZoneFunction.apply(request);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.web.servlet.i18n;
import java.util.Locale;
import java.util.TimeZone;
import java.util.function.Function;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -25,6 +26,7 @@ import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.util.WebUtils;
/**
@@ -54,6 +56,7 @@ import org.springframework.web.util.WebUtils;
* against the current {@code HttpServletRequest}.
*
* @author Juergen Hoeller
* @author Vedran Pavic
* @since 27.02.2003
* @see #setDefaultLocale
* @see #setDefaultTimeZone
@@ -85,6 +88,15 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
private String timeZoneAttributeName = TIME_ZONE_SESSION_ATTRIBUTE_NAME;
private Function<HttpServletRequest, Locale> defaultLocaleFunction = request -> {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
};
private Function<HttpServletRequest, TimeZone> defaultTimeZoneFunction = request -> getDefaultTimeZone();
/**
* Specify the name of the corresponding attribute in the {@code HttpSession},
@@ -106,12 +118,40 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
this.timeZoneAttributeName = timeZoneAttributeName;
}
/**
* Set the function used to determine the default locale for the given request,
* called if no {@link Locale} session attribute has been found.
* <p>The default implementation returns the specified default locale,
* if any, else falls back to the request's accept-header locale.
* @param defaultLocaleFunction the function used to determine the default locale
* @since 6.0
* @see #setDefaultLocale
* @see jakarta.servlet.http.HttpServletRequest#getLocale()
*/
public void setDefaultLocaleFunction(Function<HttpServletRequest, Locale> defaultLocaleFunction) {
Assert.notNull(defaultLocaleFunction, "defaultLocaleFunction must not be null");
this.defaultLocaleFunction = defaultLocaleFunction;
}
/**
* Set the function used to determine the default time zone for the given request,
* called if no {@link TimeZone} session attribute has been found.
* <p>The default implementation returns the specified default time zone,
* if any, or {@code null} otherwise.
* @param defaultTimeZoneFunction the function used to determine the default time zone
* @since 6.0
* @see #setDefaultTimeZone
*/
public void setDefaultTimeZoneFunction(Function<HttpServletRequest, TimeZone> defaultTimeZoneFunction) {
Assert.notNull(defaultTimeZoneFunction, "defaultTimeZoneFunction must not be null");
this.defaultTimeZoneFunction = defaultTimeZoneFunction;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale locale = (Locale) WebUtils.getSessionAttribute(request, this.localeAttributeName);
if (locale == null) {
locale = determineDefaultLocale(request);
locale = this.defaultLocaleFunction.apply(request);
}
return locale;
}
@@ -123,7 +163,7 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
public Locale getLocale() {
Locale locale = (Locale) WebUtils.getSessionAttribute(request, localeAttributeName);
if (locale == null) {
locale = determineDefaultLocale(request);
locale = SessionLocaleResolver.this.defaultLocaleFunction.apply(request);
}
return locale;
}
@@ -132,7 +172,7 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
public TimeZone getTimeZone() {
TimeZone timeZone = (TimeZone) WebUtils.getSessionAttribute(request, timeZoneAttributeName);
if (timeZone == null) {
timeZone = determineDefaultTimeZone(request);
timeZone = SessionLocaleResolver.this.defaultTimeZoneFunction.apply(request);
}
return timeZone;
}
@@ -167,13 +207,11 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
* @return the default locale (never {@code null})
* @see #setDefaultLocale
* @see jakarta.servlet.http.HttpServletRequest#getLocale()
* @deprecated as of 6.0, in favor of {@link #setDefaultLocaleFunction(Function)}
*/
@Deprecated
protected Locale determineDefaultLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
return this.defaultLocaleFunction.apply(request);
}
/**
@@ -184,10 +222,12 @@ public class SessionLocaleResolver extends AbstractLocaleContextResolver {
* @param request the request to resolve the time zone for
* @return the default time zone (or {@code null} if none defined)
* @see #setDefaultTimeZone
* @deprecated as of 6.0, in favor of {@link #setDefaultTimeZoneFunction(Function)}
*/
@Deprecated
@Nullable
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
return getDefaultTimeZone();
return this.defaultTimeZoneFunction.apply(request);
}
}

View File

@@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Juergen Hoeller
* @author Rick Evans
* @author Sam Brannen
* @author Vedran Pavic
*/
class CookieLocaleResolverTests {
@@ -410,4 +411,24 @@ class CookieLocaleResolverTests {
assertThat(localeCookie.getValue()).isEqualTo("");
}
@Test
void testCustomDefaultLocaleFunction() {
request.addPreferredLocale(Locale.TAIWAN);
resolver.setDefaultLocaleFunction(request -> Locale.GERMAN);
assertThat(resolver.resolveLocale(request)).isEqualTo(Locale.GERMAN);
}
@Test
void testCustomDefaultTimeZoneFunction() {
request.addPreferredLocale(Locale.TAIWAN);
resolver.setDefaultTimeZoneFunction(request -> TimeZone.getTimeZone("GMT+1"));
TimeZoneAwareLocaleContext context = (TimeZoneAwareLocaleContext) resolver.resolveLocaleContext(request);
assertThat(context.getLocale()).isEqualTo(Locale.TAIWAN);
assertThat(context.getTimeZone()).isEqualTo(TimeZone.getTimeZone("GMT+1"));
}
}

View File

@@ -17,10 +17,12 @@
package org.springframework.web.servlet.i18n;
import java.util.Locale;
import java.util.TimeZone;
import jakarta.servlet.http.HttpSession;
import org.junit.jupiter.api.Test;
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
@@ -31,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Juergen Hoeller
* @author Sam Brannen
* @author Vedran Pavic
*/
class SessionLocaleResolverTests {
@@ -94,4 +97,25 @@ class SessionLocaleResolverTests {
assertThat(resolver.resolveLocale(request)).isEqualTo(Locale.TAIWAN);
}
@Test
void testCustomDefaultLocaleFunction() {
request.addPreferredLocale(Locale.TAIWAN);
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocaleFunction(request -> Locale.GERMAN);
assertThat(resolver.resolveLocale(request)).isEqualTo(Locale.GERMAN);
}
@Test
void testCustomDefaultTimeZoneFunction() {
request.addPreferredLocale(Locale.TAIWAN);
resolver.setDefaultTimeZoneFunction(request -> TimeZone.getTimeZone("GMT+1"));
TimeZoneAwareLocaleContext context = (TimeZoneAwareLocaleContext) resolver.resolveLocaleContext(request);
assertThat(context.getLocale()).isEqualTo(Locale.TAIWAN);
assertThat(context.getTimeZone()).isEqualTo(TimeZone.getTimeZone("GMT+1"));
}
}