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 0140cf192ba2..8d6b4f0caaea 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-2017 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -22,12 +22,16 @@
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.i18n.LocaleContext;
+import org.springframework.context.i18n.SimpleLocaleContext;
import org.springframework.lang.Nullable;
/**
* Extension of {@link LocaleResolver}, adding support for a rich locale context
* (potentially including locale and time zone information).
*
+ *
Also provides pre-implemented versions of {@link #resolveLocale} and {@link #setLocale},
+ * delegating to {@link #resolveLocaleContext} and {@link #setLocaleContext}.
+ *
* @author Juergen Hoeller
* @since 4.0
* @see org.springframework.context.i18n.LocaleContext
@@ -73,4 +77,15 @@ public interface LocaleContextResolver extends LocaleResolver {
void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response,
@Nullable LocaleContext localeContext);
+ @Override
+ default Locale resolveLocale(HttpServletRequest request) {
+ Locale locale = resolveLocaleContext(request).getLocale();
+ return (locale != null ? locale : request.getLocale());
+ }
+
+ @Override
+ default void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
+ setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
+ }
+
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AbstractLocaleContextResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AbstractLocaleContextResolver.java
index 98162f6fecbb..234ae1053cd0 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AbstractLocaleContextResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AbstractLocaleContextResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -16,13 +16,8 @@
package org.springframework.web.servlet.i18n;
-import java.util.Locale;
import java.util.TimeZone;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-import org.springframework.context.i18n.SimpleLocaleContext;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.LocaleContextResolver;
@@ -30,9 +25,6 @@
* Abstract base class for {@link LocaleContextResolver} implementations.
* Provides support for a default locale and a default time zone.
*
- *
Also provides pre-implemented versions of {@link #resolveLocale} and {@link #setLocale},
- * delegating to {@link #resolveLocaleContext} and {@link #setLocaleContext}.
- *
* @author Juergen Hoeller
* @since 4.0
* @see #setDefaultLocale
@@ -59,16 +51,4 @@ public TimeZone getDefaultTimeZone() {
return this.defaultTimeZone;
}
-
- @Override
- public Locale resolveLocale(HttpServletRequest request) {
- Locale locale = resolveLocaleContext(request).getLocale();
- return (locale != null ? locale : request.getLocale());
- }
-
- @Override
- public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
- setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
- }
-
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java
index 8df4c6c51df4..47cae61aab12 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -33,7 +33,7 @@
* specified in the "accept-language" header of the HTTP request (that is,
* the locale sent by the client browser, normally that of the client's OS).
*
- *
Note: Does not support {@code setLocale}, since the accept header
+ *
Note: Does not support {@code setLocale}, since the "accept-header"
* can only be changed through changing the client's locale settings.
*
* @author Juergen Hoeller
@@ -41,13 +41,10 @@
* @since 27.02.2003
* @see jakarta.servlet.http.HttpServletRequest#getLocale()
*/
-public class AcceptHeaderLocaleResolver implements LocaleResolver {
+public class AcceptHeaderLocaleResolver extends AbstractLocaleResolver {
private final List supportedLocales = new ArrayList<>(4);
- @Nullable
- private Locale defaultLocale;
-
/**
* Configure supported locales to check against the requested locales
@@ -69,29 +66,6 @@ public List getSupportedLocales() {
return this.supportedLocales;
}
- /**
- * Configure a fixed default locale to fall back on if the request does not
- * have an "Accept-Language" header.
- * By default this is not set in which case when there is no "Accept-Language"
- * header, the default locale for the server is used as defined in
- * {@link HttpServletRequest#getLocale()}.
- * @param defaultLocale the default locale to use
- * @since 4.3
- */
- public void setDefaultLocale(@Nullable Locale defaultLocale) {
- this.defaultLocale = defaultLocale;
- }
-
- /**
- * The configured default locale, if any.
- *
This method may be overridden in subclasses.
- * @since 4.3
- */
- @Nullable
- public Locale getDefaultLocale() {
- return this.defaultLocale;
- }
-
@Override
public Locale resolveLocale(HttpServletRequest request) {
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 c4d9a85ba711..727be6ecd16d 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
@@ -18,6 +18,7 @@
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 @@
*
* @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 defaultLocaleFunction = request -> {
+ Locale defaultLocale = getDefaultLocale();
+ if (defaultLocale == null) {
+ defaultLocale = request.getLocale();
+ }
+ return defaultLocale;
+ };
+
+ private Function defaultTimeZoneFunction = request -> getDefaultTimeZone();
/**
* Create a new instance of the {@link CookieLocaleResolver} class
@@ -137,8 +148,8 @@ public boolean isLanguageTagCompliant() {
* @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 @@ protected TimeZone getDefaultTimeZone() {
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.
+ * 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 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.
+ * 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 defaultTimeZoneFunction) {
+ Assert.notNull(defaultTimeZoneFunction, "defaultTimeZoneFunction must not be null");
+ this.defaultTimeZoneFunction = defaultTimeZoneFunction;
+ }
+
@Override
public Locale resolveLocale(HttpServletRequest request) {
@@ -260,9 +300,9 @@ private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
}
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 void setLocaleContext(HttpServletRequest request, @Nullable HttpServletRe
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)));
}
@@ -334,13 +374,11 @@ protected String toLocaleValue(Locale locale) {
* @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);
}
/**
@@ -351,10 +389,12 @@ protected Locale determineDefaultLocale(HttpServletRequest request) {
* @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);
}
}
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 7ae9042a09d0..75a8a7d7dbb1 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2022 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,6 +18,7 @@
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 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 @@
* 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 defaultLocaleFunction = request -> {
+ Locale defaultLocale = getDefaultLocale();
+ if (defaultLocale == null) {
+ defaultLocale = request.getLocale();
+ }
+ return defaultLocale;
+ };
+
+ private Function defaultTimeZoneFunction = request -> getDefaultTimeZone();
/**
* Specify the name of the corresponding attribute in the {@code HttpSession},
@@ -106,12 +118,40 @@ public void setTimeZoneAttributeName(String timeZoneAttributeName) {
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.
+ * 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 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.
+ * 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 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 LocaleContext resolveLocaleContext(final HttpServletRequest request) {
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 Locale getLocale() {
public TimeZone getTimeZone() {
TimeZone timeZone = (TimeZone) WebUtils.getSessionAttribute(request, timeZoneAttributeName);
if (timeZone == null) {
- timeZone = determineDefaultTimeZone(request);
+ timeZone = SessionLocaleResolver.this.defaultTimeZoneFunction.apply(request);
}
return timeZone;
}
@@ -165,13 +205,11 @@ public void setLocaleContext(HttpServletRequest request, @Nullable HttpServletRe
* @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);
}
/**
@@ -182,10 +220,12 @@ protected Locale determineDefaultLocale(HttpServletRequest request) {
* @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);
}
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java
index 70fb14d5e2a4..2a7c0bd97137 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/CookieLocaleResolverTests.java
@@ -41,6 +41,7 @@
* @author Juergen Hoeller
* @author Rick Evans
* @author Sam Brannen
+ * @author Vedran Pavic
*/
class CookieLocaleResolverTests {
@@ -410,4 +411,24 @@ void setLocaleContextToNullWithDefault() {
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"));
+ }
+
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java
index 5b4af96191b0..8b78dfcfd625 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/SessionLocaleResolverTests.java
@@ -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 @@
*
* @author Juergen Hoeller
* @author Sam Brannen
+ * @author Vedran Pavic
*/
class SessionLocaleResolverTests {
@@ -94,4 +97,25 @@ void setLocaleToNullLocale() throws Exception {
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"));
+ }
+
}