Skip to content

Commit b89e62e

Browse files
committed
Support specifying Jackson TimeZone and Locale
Issue: SPR-12594
1 parent 4a2b6a1 commit b89e62e

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import java.text.DateFormat;
2020
import java.text.SimpleDateFormat;
21+
import java.time.ZoneId;
2122
import java.util.HashMap;
2223
import java.util.LinkedHashMap;
2324
import java.util.LinkedList;
2425
import java.util.List;
26+
import java.util.Locale;
2527
import java.util.Map;
28+
import java.util.TimeZone;
2629

2730
import com.fasterxml.jackson.annotation.JsonInclude;
2831
import com.fasterxml.jackson.core.JsonGenerator;
@@ -75,6 +78,10 @@ public class Jackson2ObjectMapperBuilder {
7578

7679
private DateFormat dateFormat;
7780

81+
private Locale locale;
82+
83+
private TimeZone timeZone;
84+
7885
private AnnotationIntrospector annotationIntrospector;
7986

8087
private PropertyNamingStrategy propertyNamingStrategy;
@@ -134,6 +141,37 @@ public Jackson2ObjectMapperBuilder simpleDateFormat(String format) {
134141
return this;
135142
}
136143

144+
/**
145+
* Override the default {@link Locale} to use for formatting.
146+
* Default value used is {@link Locale#getDefault()}.
147+
* @since 4.1.5
148+
*/
149+
public Jackson2ObjectMapperBuilder locale(Locale locale) {
150+
this.locale = locale;
151+
return this;
152+
}
153+
154+
/**
155+
* Override the default {@link TimeZone} to use for formatting.
156+
* Default value used is UTC (NOT local timezone).
157+
* @since 4.1.5
158+
*/
159+
public Jackson2ObjectMapperBuilder timeZone(TimeZone timeZone) {
160+
this.timeZone = timeZone;
161+
return this;
162+
}
163+
164+
/**
165+
* Override the default {@link TimeZone} to use for formatting.
166+
* Default value used is UTC (NOT local timezone).
167+
* @param zoneId the time-zone ID
168+
* @since 4.1.5
169+
*/
170+
public Jackson2ObjectMapperBuilder timeZone(String zoneId) {
171+
this.timeZone = TimeZone.getTimeZone(ZoneId.of(zoneId));
172+
return this;
173+
}
174+
137175
/**
138176
* Set an {@link AnnotationIntrospector} for both serialization and deserialization.
139177
*/
@@ -447,6 +485,12 @@ public void configure(ObjectMapper objectMapper) {
447485
if (this.dateFormat != null) {
448486
objectMapper.setDateFormat(this.dateFormat);
449487
}
488+
if (this.locale != null) {
489+
objectMapper.setLocale(this.locale);
490+
}
491+
if (this.timeZone != null) {
492+
objectMapper.setTimeZone(this.timeZone);
493+
}
450494

451495
if (this.annotationIntrospector != null) {
452496
objectMapper.setAnnotationIntrospector(this.annotationIntrospector);

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.text.DateFormat;
2020
import java.text.SimpleDateFormat;
2121
import java.util.List;
22+
import java.util.Locale;
2223
import java.util.Map;
24+
import java.util.TimeZone;
2325

2426
import com.fasterxml.jackson.annotation.JsonInclude;
2527
import com.fasterxml.jackson.databind.AnnotationIntrospector;
@@ -171,6 +173,34 @@ public void setSimpleDateFormat(String format) {
171173
this.builder.simpleDateFormat(format);
172174
}
173175

176+
/**
177+
* Override the default {@link Locale} to use for formatting.
178+
* Default value used is {@link Locale#getDefault()}.
179+
* @since 4.1.5
180+
*/
181+
public void setLocale(Locale locale) {
182+
this.builder.locale(locale);
183+
}
184+
185+
/**
186+
* Override the default {@link TimeZone} to use for formatting.
187+
* Default value used is UTC (NOT local timezone).
188+
* @since 4.1.5
189+
*/
190+
public void setTimeZone(TimeZone timeZone) {
191+
this.builder.timeZone(timeZone);
192+
}
193+
194+
/**
195+
* Override the default {@link TimeZone} to use for formatting.
196+
* Default value used is UTC (NOT local timezone).
197+
* @param zoneId the time-zone ID
198+
* @since 4.1.5
199+
*/
200+
public void setTimeZone(String zoneId) {
201+
this.builder.timeZone(zoneId);
202+
}
203+
174204
/**
175205
* Set an {@link AnnotationIntrospector} for both serialization and deserialization.
176206
*/

spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
package org.springframework.http.converter.json;
1818

1919
import java.text.SimpleDateFormat;
20+
import java.time.ZoneId;
21+
import java.time.zone.ZoneRulesException;
2022
import java.util.Arrays;
2123
import java.util.Collections;
2224
import java.util.Date;
2325
import java.util.HashMap;
26+
import java.util.Locale;
2427
import java.util.Map;
28+
import java.util.TimeZone;
2529

2630
import com.fasterxml.jackson.annotation.JsonInclude;
2731
import com.fasterxml.jackson.core.JsonGenerator;
@@ -166,6 +170,36 @@ public void simpleDateFormatStringSetter() {
166170
assertEquals(dateFormat, objectMapper.getDeserializationConfig().getDateFormat());
167171
}
168172

173+
@Test
174+
public void localeSetter() {
175+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().locale(Locale.FRENCH).build();
176+
assertEquals(Locale.FRENCH, objectMapper.getSerializationConfig().getLocale());
177+
assertEquals(Locale.FRENCH, objectMapper.getDeserializationConfig().getLocale());
178+
}
179+
180+
@Test
181+
public void timeZoneSetter() {
182+
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("Europe/Paris"));
183+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().timeZone(timeZone).build();
184+
assertEquals(timeZone, objectMapper.getSerializationConfig().getTimeZone());
185+
assertEquals(timeZone, objectMapper.getDeserializationConfig().getTimeZone());
186+
}
187+
188+
@Test
189+
public void timeZoneStringSetter() {
190+
String zoneId = "Europe/Paris";
191+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().timeZone(zoneId).build();
192+
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of(zoneId));
193+
assertEquals(timeZone, objectMapper.getSerializationConfig().getTimeZone());
194+
assertEquals(timeZone, objectMapper.getDeserializationConfig().getTimeZone());
195+
}
196+
197+
@Test(expected = ZoneRulesException.class)
198+
public void wrongTimeZoneStringSetter() {
199+
String zoneId = "foo";
200+
Jackson2ObjectMapperBuilder.json().timeZone(zoneId).build();
201+
}
202+
169203
@Test
170204
public void setModules() {
171205
NumberSerializer serializer1 = new NumberSerializer();

spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
package org.springframework.http.converter.json;
1818

1919
import java.text.SimpleDateFormat;
20+
import java.time.ZoneId;
21+
import java.time.zone.ZoneRulesException;
2022
import java.util.Arrays;
2123
import java.util.Collections;
2224
import java.util.Date;
2325
import java.util.HashMap;
26+
import java.util.Locale;
2427
import java.util.Map;
28+
import java.util.TimeZone;
2529

2630
import com.fasterxml.jackson.annotation.JsonInclude;
2731
import com.fasterxml.jackson.core.JsonGenerator;
@@ -161,6 +165,46 @@ public void simpleDateFormatStringSetter() {
161165
assertEquals(dateFormat, this.factory.getObject().getDeserializationConfig().getDateFormat());
162166
}
163167

168+
@Test
169+
public void localeSetter() {
170+
this.factory.setLocale(Locale.FRENCH);
171+
this.factory.afterPropertiesSet();
172+
173+
assertEquals(Locale.FRENCH, this.factory.getObject().getSerializationConfig().getLocale());
174+
assertEquals(Locale.FRENCH, this.factory.getObject().getDeserializationConfig().getLocale());
175+
}
176+
177+
@Test
178+
public void timeZoneSetter() {
179+
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("Europe/Paris"));
180+
181+
this.factory.setTimeZone(timeZone);
182+
this.factory.afterPropertiesSet();
183+
184+
assertEquals(timeZone, this.factory.getObject().getSerializationConfig().getTimeZone());
185+
assertEquals(timeZone, this.factory.getObject().getDeserializationConfig().getTimeZone());
186+
}
187+
188+
@Test
189+
public void timeZoneStringSetter() {
190+
String zoneId = "Europe/Paris";
191+
192+
this.factory.setTimeZone(zoneId);
193+
this.factory.afterPropertiesSet();
194+
195+
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of(zoneId));
196+
assertEquals(timeZone, this.factory.getObject().getSerializationConfig().getTimeZone());
197+
assertEquals(timeZone, this.factory.getObject().getDeserializationConfig().getTimeZone());
198+
}
199+
200+
@Test(expected = ZoneRulesException.class)
201+
public void wrongTimeZoneStringSetter() {
202+
String zoneId = "foo";
203+
204+
this.factory.setTimeZone(zoneId);
205+
this.factory.afterPropertiesSet();
206+
}
207+
164208
@Test
165209
public void setModules() {
166210
NumberSerializer serializer1 = new NumberSerializer();

0 commit comments

Comments
 (0)