1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.http.converter.json;
18
19 import java.io.IOException;
20 import java.io.UnsupportedEncodingException;
21 import java.text.SimpleDateFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.TimeZone;
30
31 import com.fasterxml.jackson.annotation.JsonInclude;
32 import com.fasterxml.jackson.core.JsonGenerator;
33 import com.fasterxml.jackson.core.JsonParser;
34 import com.fasterxml.jackson.core.JsonProcessingException;
35 import com.fasterxml.jackson.core.Version;
36 import com.fasterxml.jackson.databind.DeserializationFeature;
37 import com.fasterxml.jackson.databind.JsonDeserializer;
38 import com.fasterxml.jackson.databind.JsonSerializer;
39 import com.fasterxml.jackson.databind.MapperFeature;
40 import com.fasterxml.jackson.databind.Module;
41 import com.fasterxml.jackson.databind.ObjectMapper;
42 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
43 import com.fasterxml.jackson.databind.SerializationFeature;
44 import com.fasterxml.jackson.databind.SerializerProvider;
45 import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
46 import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
47 import com.fasterxml.jackson.databind.deser.BasicDeserializerFactory;
48 import com.fasterxml.jackson.databind.deser.std.DateDeserializers.DateDeserializer;
49 import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
50 import com.fasterxml.jackson.databind.module.SimpleModule;
51 import com.fasterxml.jackson.databind.module.SimpleSerializers;
52 import com.fasterxml.jackson.databind.ser.BasicSerializerFactory;
53 import com.fasterxml.jackson.databind.ser.Serializers;
54 import com.fasterxml.jackson.databind.ser.std.ClassSerializer;
55 import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
56 import com.fasterxml.jackson.databind.type.SimpleType;
57 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
58 import org.joda.time.DateTime;
59 import org.joda.time.DateTimeZone;
60 import org.junit.Before;
61 import org.junit.Test;
62
63 import org.springframework.beans.FatalBeanException;
64
65 import static org.hamcrest.Matchers.*;
66 import static org.junit.Assert.*;
67
68
69
70
71
72
73
74
75 public class Jackson2ObjectMapperFactoryBeanTests {
76
77 private static final String DATE_FORMAT = "yyyy-MM-dd";
78
79 private Jackson2ObjectMapperFactoryBean factory;
80
81
82 @Before
83 public void setUp() {
84 factory = new Jackson2ObjectMapperFactoryBean();
85 }
86
87
88 @Test
89 public void settersWithNullValues() {
90
91 factory.setSerializers((JsonSerializer<?>[]) null);
92 factory.setSerializersByType(null);
93 factory.setDeserializersByType(null);
94 factory.setFeaturesToEnable((Object[]) null);
95 factory.setFeaturesToDisable((Object[]) null);
96 }
97
98 @Test(expected = FatalBeanException.class)
99 public void unknownFeature() {
100 this.factory.setFeaturesToEnable(Boolean.TRUE);
101 this.factory.afterPropertiesSet();
102 }
103
104 @Test
105 public void booleanSetters() {
106 this.factory.setAutoDetectFields(false);
107 this.factory.setAutoDetectGettersSetters(false);
108 this.factory.setDefaultViewInclusion(false);
109 this.factory.setFailOnEmptyBeans(false);
110 this.factory.setIndentOutput(true);
111 this.factory.afterPropertiesSet();
112
113 ObjectMapper objectMapper = this.factory.getObject();
114
115 assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
116 assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
117 assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
118 assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_SETTERS));
119 assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
120 assertFalse(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
121 assertTrue(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.INDENT_OUTPUT));
122 assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
123 }
124
125 @Test
126 public void setNotNullSerializationInclusion() {
127 factory.afterPropertiesSet();
128 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
129
130 factory.setSerializationInclusion(JsonInclude.Include.NON_NULL);
131 factory.afterPropertiesSet();
132 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL);
133 }
134
135 @Test
136 public void setNotDefaultSerializationInclusion() {
137 factory.afterPropertiesSet();
138 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
139
140 factory.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
141 factory.afterPropertiesSet();
142 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_DEFAULT);
143 }
144
145 @Test
146 public void setNotEmptySerializationInclusion() {
147 factory.afterPropertiesSet();
148 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
149
150 factory.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
151 factory.afterPropertiesSet();
152 assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_EMPTY);
153 }
154
155 @Test
156 public void dateTimeFormatSetter() {
157 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
158
159 this.factory.setDateFormat(dateFormat);
160 this.factory.afterPropertiesSet();
161
162 assertEquals(dateFormat, this.factory.getObject().getSerializationConfig().getDateFormat());
163 assertEquals(dateFormat, this.factory.getObject().getDeserializationConfig().getDateFormat());
164 }
165
166 @Test
167 public void simpleDateFormatStringSetter() {
168 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
169
170 this.factory.setSimpleDateFormat(DATE_FORMAT);
171 this.factory.afterPropertiesSet();
172
173 assertEquals(dateFormat, this.factory.getObject().getSerializationConfig().getDateFormat());
174 assertEquals(dateFormat, this.factory.getObject().getDeserializationConfig().getDateFormat());
175 }
176
177 @Test
178 public void localeSetter() {
179 this.factory.setLocale(Locale.FRENCH);
180 this.factory.afterPropertiesSet();
181
182 assertEquals(Locale.FRENCH, this.factory.getObject().getSerializationConfig().getLocale());
183 assertEquals(Locale.FRENCH, this.factory.getObject().getDeserializationConfig().getLocale());
184 }
185
186 @Test
187 public void timeZoneSetter() {
188 TimeZone timeZone = TimeZone.getTimeZone("Europe/Paris");
189
190 this.factory.setTimeZone(timeZone);
191 this.factory.afterPropertiesSet();
192
193 assertEquals(timeZone, this.factory.getObject().getSerializationConfig().getTimeZone());
194 assertEquals(timeZone, this.factory.getObject().getDeserializationConfig().getTimeZone());
195 }
196
197 @Test
198 public void timeZoneStringSetter() {
199 String zoneId = "Europe/Paris";
200
201 this.factory.setTimeZone(TimeZone.getTimeZone(zoneId));
202 this.factory.afterPropertiesSet();
203
204 TimeZone timeZone = TimeZone.getTimeZone(zoneId);
205 assertEquals(timeZone, this.factory.getObject().getSerializationConfig().getTimeZone());
206 assertEquals(timeZone, this.factory.getObject().getDeserializationConfig().getTimeZone());
207 }
208
209 @Test
210 public void wrongTimeZoneStringSetter() {
211 String zoneId = "foo";
212
213 this.factory.setTimeZone(TimeZone.getTimeZone(zoneId));
214 this.factory.afterPropertiesSet();
215
216 TimeZone timeZone = TimeZone.getTimeZone("GMT");
217 assertEquals(timeZone, this.factory.getObject().getSerializationConfig().getTimeZone());
218 assertEquals(timeZone, this.factory.getObject().getDeserializationConfig().getTimeZone());
219 }
220
221 @Test
222 public void setModules() {
223 NumberSerializer serializer1 = new NumberSerializer();
224 SimpleModule module = new SimpleModule();
225 module.addSerializer(Integer.class, serializer1);
226
227 this.factory.setModules(Arrays.asList(new Module[]{module}));
228 this.factory.afterPropertiesSet();
229 ObjectMapper objectMapper = this.factory.getObject();
230
231 Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
232 assertTrue(serializers.findSerializer(null, SimpleType.construct(Integer.class), null) == serializer1);
233 }
234
235 @Test
236 public void defaultModules() throws JsonProcessingException, UnsupportedEncodingException {
237 this.factory.afterPropertiesSet();
238 ObjectMapper objectMapper = this.factory.getObject();
239
240 Long timestamp = 1322903730000L;
241 DateTime dateTime = new DateTime(timestamp, DateTimeZone.UTC);
242 assertEquals(timestamp.toString(), new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
243 }
244
245 @Test
246 public void customizeDefaultModulesWithModuleClass() throws JsonProcessingException, UnsupportedEncodingException {
247 this.factory.setModulesToInstall(CustomIntegerModule.class);
248 this.factory.afterPropertiesSet();
249 ObjectMapper objectMapper = this.factory.getObject();
250
251 DateTime dateTime = new DateTime(1322903730000L, DateTimeZone.UTC);
252 assertEquals("1322903730000", new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
253 assertThat(new String(objectMapper.writeValueAsBytes(new Integer(4)), "UTF-8"), containsString("customid"));
254 }
255
256 @Test
257 public void customizeDefaultModulesWithSerializer() throws JsonProcessingException, UnsupportedEncodingException {
258 Map<Class<?>, JsonSerializer<?>> serializers = new HashMap<>();
259 serializers.put(Integer.class, new CustomIntegerSerializer());
260
261 this.factory.setSerializersByType(serializers);
262 this.factory.afterPropertiesSet();
263 ObjectMapper objectMapper = this.factory.getObject();
264
265 DateTime dateTime = new DateTime(1322903730000L, DateTimeZone.UTC);
266 assertEquals("1322903730000", new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
267 assertThat(new String(objectMapper.writeValueAsBytes(new Integer(4)), "UTF-8"), containsString("customid"));
268 }
269
270 @Test
271 public void simpleSetup() {
272 this.factory.afterPropertiesSet();
273
274 assertNotNull(this.factory.getObject());
275 assertTrue(this.factory.isSingleton());
276 assertEquals(ObjectMapper.class, this.factory.getObjectType());
277 }
278
279 @Test
280 public void undefinedObjectType() {
281 assertEquals(null, this.factory.getObjectType());
282 }
283
284 private static SerializerFactoryConfig getSerializerFactoryConfig(ObjectMapper objectMapper) {
285 return ((BasicSerializerFactory) objectMapper.getSerializerFactory()).getFactoryConfig();
286 }
287
288 private static DeserializerFactoryConfig getDeserializerFactoryConfig(ObjectMapper objectMapper) {
289 return ((BasicDeserializerFactory) objectMapper.getDeserializationContext().getFactory()).getFactoryConfig();
290 }
291
292 @Test
293 public void propertyNamingStrategy() {
294 PropertyNamingStrategy strategy = new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy();
295 this.factory.setPropertyNamingStrategy(strategy);
296 this.factory.afterPropertiesSet();
297
298 assertSame(strategy, this.factory.getObject().getSerializationConfig().getPropertyNamingStrategy());
299 assertSame(strategy, this.factory.getObject().getDeserializationConfig().getPropertyNamingStrategy());
300 }
301
302 @Test
303 public void setMixIns() {
304 Class<?> target = String.class;
305 Class<?> mixinSource = Object.class;
306 Map<Class<?>, Class<?>> mixIns = new HashMap<Class<?>, Class<?>>();
307 mixIns.put(target, mixinSource);
308
309 this.factory.setMixIns(mixIns);
310 this.factory.afterPropertiesSet();
311 ObjectMapper objectMapper = this.factory.getObject();
312
313 assertEquals(1, objectMapper.mixInCount());
314 assertSame(mixinSource, objectMapper.findMixInClassFor(target));
315 }
316
317 @Test
318 public void completeSetup() {
319 NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance;
320 ObjectMapper objectMapper = new ObjectMapper();
321
322 factory.setObjectMapper(objectMapper);
323 assertTrue(this.factory.isSingleton());
324 assertEquals(ObjectMapper.class, this.factory.getObjectType());
325
326 Map<Class<?>, JsonDeserializer<?>> deserializers = new HashMap<Class<?>, JsonDeserializer<?>>();
327 deserializers.put(Date.class, new DateDeserializer());
328
329 JsonSerializer<Class<?>> serializer1 = new ClassSerializer();
330 JsonSerializer<Number> serializer2 = new NumberSerializer();
331
332 factory.setModules(new ArrayList<>());
333 factory.setSerializers(serializer1);
334 factory.setSerializersByType(Collections.<Class<?>, JsonSerializer<?>> singletonMap(Boolean.class, serializer2));
335 factory.setDeserializersByType(deserializers);
336 factory.setAnnotationIntrospector(annotationIntrospector);
337
338 this.factory.setFeaturesToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS,
339 DeserializationFeature.UNWRAP_ROOT_VALUE,
340 JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
341 JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
342
343 this.factory.setFeaturesToDisable(MapperFeature.AUTO_DETECT_GETTERS,
344 MapperFeature.AUTO_DETECT_FIELDS,
345 JsonParser.Feature.AUTO_CLOSE_SOURCE,
346 JsonGenerator.Feature.QUOTE_FIELD_NAMES);
347
348 assertFalse(getSerializerFactoryConfig(objectMapper).hasSerializers());
349 assertFalse(getDeserializerFactoryConfig(objectMapper).hasDeserializers());
350
351 this.factory.setSerializationInclusion(JsonInclude.Include.NON_NULL);
352 this.factory.afterPropertiesSet();
353
354 assertTrue(objectMapper == this.factory.getObject());
355 assertTrue(getSerializerFactoryConfig(objectMapper).hasSerializers());
356 assertTrue(getDeserializerFactoryConfig(objectMapper).hasDeserializers());
357
358 Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
359 assertTrue(serializers.findSerializer(null, SimpleType.construct(Class.class), null) == serializer1);
360 assertTrue(serializers.findSerializer(null, SimpleType.construct(Boolean.class), null) == serializer2);
361 assertNull(serializers.findSerializer(null, SimpleType.construct(Number.class), null));
362
363 assertTrue(annotationIntrospector == objectMapper.getSerializationConfig().getAnnotationIntrospector());
364 assertTrue(annotationIntrospector == objectMapper.getDeserializationConfig().getAnnotationIntrospector());
365
366 assertTrue(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
367 assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
368 assertTrue(objectMapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
369 assertTrue(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
370
371 assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
372 assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
373 assertFalse(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
374 assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
375 assertFalse(objectMapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
376 assertFalse(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
377 assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL);
378 }
379
380 @Test
381 public void xmlMapper() {
382 this.factory.setObjectMapper(new XmlMapper());
383 this.factory.afterPropertiesSet();
384
385 assertNotNull(this.factory.getObject());
386 assertTrue(this.factory.isSingleton());
387 assertEquals(XmlMapper.class, this.factory.getObjectType());
388 }
389
390 @Test
391 public void createXmlMapper() {
392 this.factory.setCreateXmlMapper(true);
393 this.factory.afterPropertiesSet();
394
395 assertNotNull(this.factory.getObject());
396 assertTrue(this.factory.isSingleton());
397 assertEquals(XmlMapper.class, this.factory.getObjectType());
398 }
399
400
401 public static class CustomIntegerModule extends Module {
402
403 @Override
404 public String getModuleName() {
405 return this.getClass().getSimpleName();
406 }
407
408 @Override
409 public Version version() {
410 return Version.unknownVersion();
411 }
412
413 @Override
414 public void setupModule(SetupContext context) {
415 SimpleSerializers serializers = new SimpleSerializers();
416 serializers.addSerializer(Integer.class, new CustomIntegerSerializer());
417 context.addSerializers(serializers);
418 }
419 }
420
421
422 public static class CustomIntegerSerializer extends JsonSerializer<Integer> {
423
424 @Override
425 public void serialize(Integer value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
426 gen.writeStartObject();
427 gen.writeNumberField("customid", value);
428 gen.writeEndObject();
429 }
430 }
431
432 }