From 47d40053a41466bb2728229bc4cf0c73968d0ced Mon Sep 17 00:00:00 2001 From: Dmitry Katsubo Date: Tue, 6 Aug 2013 17:44:47 +0200 Subject: [PATCH] Add Jackson serialization inclusion to FactoryBean Issue: SPR-10810 --- .../json/Jackson2ObjectMapperFactoryBean.java | 24 +++- .../Jackson2ObjectMapperFactoryBeanTests.java | 106 +++++++++++++----- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java index 6bfebfe1924..7eb7acdd987 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java @@ -22,6 +22,12 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; + +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.AnnotationIntrospector; @@ -33,11 +39,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.springframework.beans.FatalBeanException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - /** * A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} with setters * to enable or disable Jackson features from within XML configuration. @@ -112,6 +113,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean, JsonDeserializer> deserializers = new LinkedHashMap, JsonDeserializer>(); + private JsonInclude.Include serializationInclusion; + /** * Set the ObjectMapper instance to use. If not set, the ObjectMapper will @@ -247,6 +250,13 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean[]) null); + factory.setSerializersByType(null); + factory.setDeserializersByType(null); + factory.setFeaturesToEnable((Object[]) null); + factory.setFeaturesToDisable((Object[]) null); } @Test(expected = FatalBeanException.class) @@ -89,6 +96,37 @@ public class Jackson2ObjectMapperFactoryBeanTests { assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_SETTERS)); assertFalse(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); assertTrue(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.INDENT_OUTPUT)); + assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS); + } + + @Test + public void testSetNotNullSerializationInclusion() { + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS); + + factory.setSerializationInclusion(JsonInclude.Include.NON_NULL); + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL); + } + + @Test + public void testSetNotDefaultSerializationInclusion() { + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS); + + factory.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_DEFAULT); + } + + @Test + public void testSetNotEmptySerializationInclusion() { + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS); + + factory.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + factory.afterPropertiesSet(); + assertTrue(factory.getObject().getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_EMPTY); } @Test @@ -122,19 +160,12 @@ public class Jackson2ObjectMapperFactoryBeanTests { assertEquals(ObjectMapper.class, this.factory.getObjectType()); } - /** - * TODO: Remove use of {@link DirectFieldAccessor} with getters. - * See issue#65. - */ private static final SerializerFactoryConfig getSerializerFactoryConfig(ObjectMapper objectMapper) { - Object factoryProp = new DirectFieldAccessor(objectMapper).getPropertyValue("_serializerFactory"); - return (SerializerFactoryConfig) new DirectFieldAccessor(factoryProp).getPropertyValue("_factoryConfig"); + return ((BasicSerializerFactory) objectMapper.getSerializerFactory()).getFactoryConfig(); } private static final DeserializerFactoryConfig getDeserializerFactoryConfig(ObjectMapper objectMapper) { - Object contextProp = new DirectFieldAccessor(objectMapper).getPropertyValue("_deserializationContext"); - Object factoryProp = new DirectFieldAccessor(contextProp).getPropertyValue("_factory"); - return (DeserializerFactoryConfig) new DirectFieldAccessor(factoryProp).getPropertyValue("_factoryConfig"); + return ((BasicDeserializerFactory) objectMapper.getDeserializationContext().getFactory()).getFactoryConfig(); } @Test @@ -148,19 +179,22 @@ public class Jackson2ObjectMapperFactoryBeanTests { Map, JsonDeserializer> deserializers = new HashMap, JsonDeserializer>(); deserializers.put(Date.class, new DateDeserializer()); - this.factory.setObjectMapper(objectMapper); - this.factory.setSerializers(new ClassSerializer()); - this.factory.setDeserializersByType(deserializers); - this.factory.setAnnotationIntrospector(annotationIntrospector); + factory.setObjectMapper(objectMapper); + + JsonSerializer serializer1 = new ClassSerializer(); + JsonSerializer serializer2 = new NumberSerializer(); - this.factory.setFeaturesToEnable( - SerializationFeature.FAIL_ON_EMPTY_BEANS, + factory.setSerializers(serializer1); + factory.setSerializersByType(Collections., JsonSerializer> singletonMap(Boolean.class, serializer2)); + factory.setDeserializersByType(deserializers); + factory.setAnnotationIntrospector(annotationIntrospector); + + this.factory.setFeaturesToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS, DeserializationFeature.UNWRAP_ROOT_VALUE, JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS); - this.factory.setFeaturesToDisable( - MapperFeature.AUTO_DETECT_GETTERS, + this.factory.setFeaturesToDisable(MapperFeature.AUTO_DETECT_GETTERS, MapperFeature.AUTO_DETECT_FIELDS, JsonParser.Feature.AUTO_CLOSE_SOURCE, JsonGenerator.Feature.QUOTE_FIELD_NAMES); @@ -168,6 +202,8 @@ public class Jackson2ObjectMapperFactoryBeanTests { assertFalse(getSerializerFactoryConfig(objectMapper).hasSerializers()); assertFalse(getDeserializerFactoryConfig(objectMapper).hasDeserializers()); + this.factory.setSerializationInclusion(JsonInclude.Include.NON_NULL); + this.factory.afterPropertiesSet(); assertTrue(objectMapper == this.factory.getObject()); @@ -175,17 +211,25 @@ public class Jackson2ObjectMapperFactoryBeanTests { assertTrue(getSerializerFactoryConfig(objectMapper).hasSerializers()); assertTrue(getDeserializerFactoryConfig(objectMapper).hasDeserializers()); + Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next(); + + assertTrue(serializers.findSerializer(null, SimpleType.construct(Class.class), null) == serializer1); + assertTrue(serializers.findSerializer(null, SimpleType.construct(Boolean.class), null) == serializer2); + assertNull(serializers.findSerializer(null, SimpleType.construct(Number.class), null)); + assertTrue(annotationIntrospector == objectMapper.getSerializationConfig().getAnnotationIntrospector()); assertTrue(annotationIntrospector == objectMapper.getDeserializationConfig().getAnnotationIntrospector()); assertTrue(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE)); - assertTrue(objectMapper.getJsonFactory().isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)); - assertTrue(objectMapper.getJsonFactory().isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS)); + assertTrue(objectMapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)); + assertTrue(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS)); assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_GETTERS)); assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS)); - assertFalse(objectMapper.getJsonFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)); - assertFalse(objectMapper.getJsonFactory().isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES)); + assertFalse(objectMapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)); + assertFalse(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES)); + + assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL); } }