Skip to content

Commit 271b0ab

Browse files
committed
LocaleContextHolder provides support for framework-level default settings
Issue: SPR-15017 (cherry picked from commit 23f0418)
1 parent f0c3d50 commit 271b0ab

File tree

4 files changed

+73
-15
lines changed

4 files changed

+73
-15
lines changed

spring-context/src/main/java/org/springframework/context/i18n/LocaleContextHolder.java

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,10 +44,16 @@
4444
public abstract class LocaleContextHolder {
4545

4646
private static final ThreadLocal<LocaleContext> localeContextHolder =
47-
new NamedThreadLocal<LocaleContext>("Locale context");
47+
new NamedThreadLocal<LocaleContext>("LocaleContext");
4848

4949
private static final ThreadLocal<LocaleContext> inheritableLocaleContextHolder =
50-
new NamedInheritableThreadLocal<LocaleContext>("Locale context");
50+
new NamedInheritableThreadLocal<LocaleContext>("LocaleContext");
51+
52+
// Shared default locale at the framework level
53+
private static Locale defaultLocale;
54+
55+
// Shared default time zone at the framework level
56+
private static TimeZone defaultTimeZone;
5157

5258

5359
/**
@@ -152,18 +158,38 @@ else if (locale != null) {
152158
setLocaleContext(localeContext, inheritable);
153159
}
154160

161+
/**
162+
* Set a shared default locale at the framework level,
163+
* as an alternative to the JVM-wide default locale.
164+
* <p><b>NOTE:</b> This can be useful to set an application-level
165+
* default locale which differs from the JVM-wide default locale.
166+
* However, this requires each such application to operate against
167+
* locally deployed Spring Framework jars. Do not deploy Spring
168+
* as a shared library at the server level in such a scenario!
169+
* @param locale the default locale (or {@code null} for none,
170+
* letting lookups fall back to {@link Locale#getDefault()})
171+
* @since 4.3.5
172+
* @see #getLocale()
173+
* @see Locale#getDefault()
174+
*/
175+
public static void setDefaultLocale(Locale locale) {
176+
LocaleContextHolder.defaultLocale = locale;
177+
}
178+
155179
/**
156180
* Return the Locale associated with the current thread, if any,
157-
* or the system default Locale else. This is effectively a
181+
* or the system default Locale otherwise. This is effectively a
158182
* replacement for {@link java.util.Locale#getDefault()},
159183
* able to optionally respect a user-level Locale setting.
160-
* <p>Note: This method has a fallback to the system default Locale.
184+
* <p>Note: This method has a fallback to the shared default Locale,
185+
* either at the framework level or at the JVM-wide system level.
161186
* If you'd like to check for the raw LocaleContext content
162187
* (which may indicate no specific locale through {@code null}, use
163188
* {@link #getLocaleContext()} and call {@link LocaleContext#getLocale()}
164189
* @return the current Locale, or the system default Locale if no
165190
* specific Locale has been associated with the current thread
166191
* @see LocaleContext#getLocale()
192+
* @see #setDefaultLocale(Locale)
167193
* @see java.util.Locale#getDefault()
168194
*/
169195
public static Locale getLocale() {
@@ -174,7 +200,7 @@ public static Locale getLocale() {
174200
return locale;
175201
}
176202
}
177-
return Locale.getDefault();
203+
return (defaultLocale != null ? defaultLocale : Locale.getDefault());
178204
}
179205

180206
/**
@@ -217,19 +243,39 @@ else if (locale != null) {
217243
setLocaleContext(localeContext, inheritable);
218244
}
219245

246+
/**
247+
* Set a shared default time zone at the framework level,
248+
* as an alternative to the JVM-wide default time zone.
249+
* <p><b>NOTE:</b> This can be useful to set an application-level
250+
* default time zone which differs from the JVM-wide default time zone.
251+
* However, this requires each such application to operate against
252+
* locally deployed Spring Framework jars. Do not deploy Spring
253+
* as a shared library at the server level in such a scenario!
254+
* @param timeZone the default time zone (or {@code null} for none,
255+
* letting lookups fall back to {@link TimeZone#getDefault()})
256+
* @since 4.3.5
257+
* @see #getTimeZone()
258+
* @see TimeZone#getDefault()
259+
*/
260+
public static void setDefaultTimeZone(TimeZone timeZone) {
261+
defaultTimeZone = timeZone;
262+
}
263+
220264
/**
221265
* Return the TimeZone associated with the current thread, if any,
222-
* or the system default TimeZone else. This is effectively a
266+
* or the system default TimeZone otherwise. This is effectively a
223267
* replacement for {@link java.util.TimeZone#getDefault()},
224268
* able to optionally respect a user-level TimeZone setting.
225-
* <p>Note: This method has a fallback to the system default Locale.
269+
* <p>Note: This method has a fallback to the shared default TimeZone,
270+
* either at the framework level or at the JVM-wide system level.
226271
* If you'd like to check for the raw LocaleContext content
227272
* (which may indicate no specific time zone through {@code null}, use
228273
* {@link #getLocaleContext()} and call {@link TimeZoneAwareLocaleContext#getTimeZone()}
229274
* after downcasting to {@link TimeZoneAwareLocaleContext}.
230275
* @return the current TimeZone, or the system default TimeZone if no
231276
* specific TimeZone has been associated with the current thread
232277
* @see TimeZoneAwareLocaleContext#getTimeZone()
278+
* @see #setDefaultTimeZone(TimeZone)
233279
* @see java.util.TimeZone#getDefault()
234280
*/
235281
public static TimeZone getTimeZone() {
@@ -240,7 +286,7 @@ public static TimeZone getTimeZone() {
240286
return timeZone;
241287
}
242288
}
243-
return TimeZone.getDefault();
289+
return (defaultTimeZone != null ? defaultTimeZone : TimeZone.getDefault());
244290
}
245291

246292
}

spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeContextHolder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,11 +29,12 @@
2929
* @author Keith Donald
3030
* @author Juergen Hoeller
3131
* @since 3.0
32+
* @see org.springframework.context.i18n.LocaleContextHolder
3233
*/
3334
public final class JodaTimeContextHolder {
3435

3536
private static final ThreadLocal<JodaTimeContext> jodaTimeContextHolder =
36-
new NamedThreadLocal<JodaTimeContext>("JodaTime Context");
37+
new NamedThreadLocal<JodaTimeContext>("JodaTimeContext");
3738

3839

3940
/**

spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeContextHolder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,12 +27,13 @@
2727
*
2828
* @author Juergen Hoeller
2929
* @since 4.0
30+
* @see org.springframework.context.i18n.LocaleContextHolder
3031
*/
3132
@UsesJava8
3233
public final class DateTimeContextHolder {
3334

3435
private static final ThreadLocal<DateTimeContext> dateTimeContextHolder =
35-
new NamedThreadLocal<DateTimeContext>("DateTime Context");
36+
new NamedThreadLocal<DateTimeContext>("DateTimeContext");
3637

3738

3839
/**

spring-context/src/test/java/org/springframework/context/i18n/LocaleContextHolderTests.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -80,6 +80,11 @@ public void testSetLocale() {
8080
assertNull(LocaleContextHolder.getLocaleContext());
8181
assertEquals(Locale.getDefault(), LocaleContextHolder.getLocale());
8282
assertEquals(TimeZone.getDefault(), LocaleContextHolder.getTimeZone());
83+
84+
LocaleContextHolder.setDefaultLocale(Locale.GERMAN);
85+
assertEquals(Locale.GERMAN, LocaleContextHolder.getLocale());
86+
LocaleContextHolder.setDefaultLocale(null);
87+
assertEquals(Locale.getDefault(), LocaleContextHolder.getLocale());
8388
}
8489

8590
@Test
@@ -99,9 +104,14 @@ public void testSetTimeZone() {
99104
assertEquals(TimeZone.getTimeZone("GMT+2"), ((TimeZoneAwareLocaleContext) LocaleContextHolder.getLocaleContext()).getTimeZone());
100105

101106
LocaleContextHolder.setTimeZone(null);
107+
assertNull(LocaleContextHolder.getLocaleContext());
102108
assertEquals(Locale.getDefault(), LocaleContextHolder.getLocale());
103109
assertEquals(TimeZone.getDefault(), LocaleContextHolder.getTimeZone());
104-
assertNull(LocaleContextHolder.getLocaleContext());
110+
111+
LocaleContextHolder.setDefaultTimeZone(TimeZone.getTimeZone("GMT+1"));
112+
assertEquals(TimeZone.getTimeZone("GMT+1"), LocaleContextHolder.getTimeZone());
113+
LocaleContextHolder.setDefaultTimeZone(null);
114+
assertEquals(TimeZone.getDefault(), LocaleContextHolder.getTimeZone());
105115
}
106116

107117
@Test

0 commit comments

Comments
 (0)