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