@ -18,15 +18,10 @@ package org.springframework.http.converter.json;
@@ -18,15 +18,10 @@ package org.springframework.http.converter.json;
import java.text.DateFormat ;
import java.text.SimpleDateFormat ;
import java.util.HashMap ;
import java.util.LinkedHashMap ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Map ;
import com.fasterxml.jackson.annotation.JsonInclude ;
import com.fasterxml.jackson.core.JsonGenerator ;
import com.fasterxml.jackson.core.JsonParser ;
import com.fasterxml.jackson.databind.AnnotationIntrospector ;
import com.fasterxml.jackson.databind.DeserializationFeature ;
import com.fasterxml.jackson.databind.JsonDeserializer ;
@ -36,16 +31,11 @@ import com.fasterxml.jackson.databind.Module;
@@ -36,16 +31,11 @@ import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper ;
import com.fasterxml.jackson.databind.PropertyNamingStrategy ;
import com.fasterxml.jackson.databind.SerializationFeature ;
import com.fasterxml.jackson.databind.module.SimpleModule ;
import com.fasterxml.jackson.dataformat.xml.XmlMapper ;
import org.springframework.beans.BeanUtils ;
import org.springframework.beans.FatalBeanException ;
import org.springframework.beans.factory.BeanClassLoaderAware ;
import org.springframework.beans.factory.FactoryBean ;
import org.springframework.beans.factory.InitializingBean ;
import org.springframework.util.Assert ;
import org.springframework.util.ClassUtils ;
/ * *
* A { @link FactoryBean } for creating a Jackson 2 . x { @link ObjectMapper } ( default ) or
@ -54,8 +44,8 @@ import org.springframework.util.ClassUtils;
@@ -54,8 +44,8 @@ import org.springframework.util.ClassUtils;
*
* < p > It customizes Jackson defaults properties with the following ones :
* < ul >
* < li > { @link MapperFeature # DEFAULT_VIEW_INCLUSION } is disabled < / li >
* < li > { @link DeserializationFeature # FAIL_ON_UNKNOWN_PROPERTIES } is disabled < / li >
* < li > { @link MapperFeature # DEFAULT_VIEW_INCLUSION } is disabled < / li >
* < li > { @link DeserializationFeature # FAIL_ON_UNKNOWN_PROPERTIES } is disabled < / li >
* < / ul >
*
* < p > Example usage with
@ -132,31 +122,9 @@ import org.springframework.util.ClassUtils;
@@ -132,31 +122,9 @@ import org.springframework.util.ClassUtils;
* /
public class Jackson2ObjectMapperFactoryBean implements FactoryBean < ObjectMapper > , BeanClassLoaderAware , InitializingBean {
private ObjectMapper objectMapper ;
private boolean createXmlMapper = false ;
private DateFormat dateFormat ;
private JsonInclude . Include serializationInclusion ;
private AnnotationIntrospector annotationIntrospector ;
private final Map < Class < ? > , JsonSerializer < ? > > serializers = new LinkedHashMap < Class < ? > , JsonSerializer < ? > > ( ) ;
private final Map < Class < ? > , JsonDeserializer < ? > > deserializers = new LinkedHashMap < Class < ? > , JsonDeserializer < ? > > ( ) ;
private final Map < Object , Boolean > features = new HashMap < Object , Boolean > ( ) ;
private List < Module > modules ;
private Class < ? extends Module > [ ] modulesToInstall ;
private boolean findModulesViaServiceLoader ;
private final Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder . json ( ) ;
private PropertyNamingStrategy propertyNamingStrategy ;
private ClassLoader beanClassLoader ;
private ObjectMapper objectMapper ;
/ * *
@ -170,9 +138,10 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -170,9 +138,10 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/ * *
* If set to true and no custom { @link ObjectMapper } has been set , a { @link XmlMapper }
* will be created using its default constructor .
* @since 4 . 1
* /
public void setCreateXmlMapper ( boolean createXmlMapper ) {
this . createXmlMapper = createXmlMapper ;
this . builder . createXmlMapper ( createXmlMapper ) ;
}
/ * *
@ -182,7 +151,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -182,7 +151,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see # setSimpleDateFormat ( String )
* /
public void setDateFormat ( DateFormat dateFormat ) {
this . dateFormat = dateFormat ;
this . builder . dateFormat ( dateFormat ) ;
}
/ * *
@ -192,14 +161,23 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -192,14 +161,23 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see # setDateFormat ( DateFormat )
* /
public void setSimpleDateFormat ( String format ) {
this . dateFormat = new S impleDateFormat( format ) ;
this . builder . s impleDateFormat( format ) ;
}
/ * *
* Set an { @link AnnotationIntrospector } for both serialization and deserialization .
* /
public void setAnnotationIntrospector ( AnnotationIntrospector annotationIntrospector ) {
this . annotationIntrospector = annotationIntrospector ;
this . builder . annotationIntrospector ( annotationIntrospector ) ;
}
/ * *
* Specify a { @link com . fasterxml . jackson . databind . PropertyNamingStrategy } to
* configure the { @link ObjectMapper } with .
* @since 4 . 0 . 2
* /
public void setPropertyNamingStrategy ( PropertyNamingStrategy propertyNamingStrategy ) {
this . builder . propertyNamingStrategy ( propertyNamingStrategy ) ;
}
/ * *
@ -207,7 +185,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -207,7 +185,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . annotation . JsonInclude . Include
* /
public void setSerializationInclusion ( JsonInclude . Include serializationInclusion ) {
this . serializationInclusion = serializationInclusion ;
this . builder . serializationInclusion ( serializationInclusion ) ;
}
/ * *
@ -217,14 +195,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -217,14 +195,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see # setSerializersByType ( Map )
* /
public void setSerializers ( JsonSerializer < ? > . . . serializers ) {
if ( serializers ! = null ) {
for ( JsonSerializer < ? > serializer : serializers ) {
Class < ? > handledType = serializer . handledType ( ) ;
Assert . isTrue ( handledType ! = null & & handledType ! = Object . class ,
"Unknown handled type in " + serializer . getClass ( ) . getName ( ) ) ;
this . serializers . put ( serializer . handledType ( ) , serializer ) ;
}
}
this . builder . serializers ( serializers ) ;
}
/ * *
@ -232,25 +203,21 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -232,25 +203,21 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see # setSerializers ( JsonSerializer . . . )
* /
public void setSerializersByType ( Map < Class < ? > , JsonSerializer < ? > > serializers ) {
if ( serializers ! = null ) {
this . serializers . putAll ( serializers ) ;
}
this . builder . serializersByType ( serializers ) ;
}
/ * *
* Configure custom deserializers for the given types .
* /
public void setDeserializersByType ( Map < Class < ? > , JsonDeserializer < ? > > deserializers ) {
if ( deserializers ! = null ) {
this . deserializers . putAll ( deserializers ) ;
}
this . builder . deserializersByType ( deserializers ) ;
}
/ * *
* Shortcut for { @link MapperFeature # AUTO_DETECT_FIELDS } option .
* /
public void setAutoDetectFields ( boolean autoDetectFields ) {
this . features . put ( MapperFeature . AUTO_DETECT_FIELDS , autoDetectFields ) ;
this . builder . autoDetectFields ( autoDetectFields ) ;
}
/ * *
@ -258,36 +225,37 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -258,36 +225,37 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* { @link MapperFeature # AUTO_DETECT_GETTERS } option .
* /
public void setAutoDetectGettersSetters ( boolean autoDetectGettersSetters ) {
this . features . put ( MapperFeature . AUTO_DETECT_GETTERS , autoDetectGettersSetters ) ;
this . features . put ( MapperFeature . AUTO_DETECT_SETTERS , autoDetectGettersSetters ) ;
this . builder . autoDetectGettersSetters ( autoDetectGettersSetters ) ;
}
/ * *
* Shortcut for { @link DeserializationFeature # FAIL_ON_UNKNOWN_PROPERTIES } option .
* Shortcut for { @link MapperFeature # DEFAULT_VIEW_INCLUSION } option .
* @since 4 . 1
* /
public void setFailOnUnknownProperties ( boolean failOnUnknownProperties ) {
this . features . put ( DeserializationFeature . FAIL_ON_UNKNOWN_PROPERTIES , failOnUnknownProperties ) ;
public void setDefaultViewInclusion ( boolean defaultViewInclusion ) {
this . builder . defaultViewInclusion ( defaultViewInclusion ) ;
}
/ * *
* Shortcut for { @link MapperFeature # DEFAULT_VIEW_INCLUSION } option .
* Shortcut for { @link DeserializationFeature # FAIL_ON_UNKNOWN_PROPERTIES } option .
* @since 4 . 1 . 1
* /
public void setDefaultViewInclusion ( boolean defaultViewInclusion ) {
this . features . put ( MapperFeature . DEFAULT_VIEW_INCLUSION , defaultViewInclusion ) ;
public void setFailOnUnknownProperties ( boolean failOnUnknownProperties ) {
this . builder . failOnUnknownProperties ( failOnUnknownProperties ) ;
}
/ * *
* Shortcut for { @link SerializationFeature # FAIL_ON_EMPTY_BEANS } option .
* /
public void setFailOnEmptyBeans ( boolean failOnEmptyBeans ) {
this . features . put ( SerializationFeature . FAIL_ON_EMPTY_BEANS , failOnEmptyBeans ) ;
this . builder . failOnEmptyBeans ( failOnEmptyBeans ) ;
}
/ * *
* Shortcut for { @link SerializationFeature # INDENT_OUTPUT } option .
* /
public void setIndentOutput ( boolean indentOutput ) {
this . features . put ( SerializationFeature . INDENT_OUTPUT , indentOutput ) ;
this . builder . indentOutput ( indentOutput ) ;
}
/ * *
@ -299,11 +267,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -299,11 +267,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . databind . MapperFeature
* /
public void setFeaturesToEnable ( Object . . . featuresToEnable ) {
if ( featuresToEnable ! = null ) {
for ( Object feature : featuresToEnable ) {
this . features . put ( feature , Boolean . TRUE ) ;
}
}
this . builder . featuresToEnable ( featuresToEnable ) ;
}
/ * *
@ -315,11 +279,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -315,11 +279,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . databind . MapperFeature
* /
public void setFeaturesToDisable ( Object . . . featuresToDisable ) {
if ( featuresToDisable ! = null ) {
for ( Object feature : featuresToDisable ) {
this . features . put ( feature , Boolean . FALSE ) ;
}
}
this . builder . featuresToDisable ( featuresToDisable ) ;
}
/ * *
@ -333,7 +293,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -333,7 +293,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . databind . Module
* /
public void setModules ( List < Module > modules ) {
this . modules = new LinkedList < Module > ( modules ) ;
this . builder . modules ( modules ) ;
}
/ * *
@ -347,7 +307,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -347,7 +307,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . databind . Module
* /
public void setModulesToInstall ( Class < ? extends Module > . . . modules ) {
this . modulesToInstall = modules ;
this . builder . modulesToInstall ( modules ) ;
}
/ * *
@ -360,165 +320,23 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -360,165 +320,23 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
* @see com . fasterxml . jackson . databind . ObjectMapper # findModules ( )
* /
public void setFindModulesViaServiceLoader ( boolean findModules ) {
this . findModulesViaServiceLoader = findModules ;
}
/ * *
* Specify a { @link com . fasterxml . jackson . databind . PropertyNamingStrategy } to
* configure the { @link ObjectMapper } with .
* @since 4 . 0 . 2
* /
public void setPropertyNamingStrategy ( PropertyNamingStrategy propertyNamingStrategy ) {
this . propertyNamingStrategy = propertyNamingStrategy ;
this . builder . findModulesViaServiceLoader ( findModules ) ;
}
@Override
public void setBeanClassLoader ( ClassLoader beanClassLoader ) {
this . beanClassLoader = beanClassLoader ;
this . builder . moduleClassLoader ( beanClassLoader ) ;
}
@Override
@SuppressWarnings ( "unchecked" )
public void afterPropertiesSet ( ) {
if ( this . objectMapper = = null ) {
if ( this . createXmlMapper ) {
ClassLoader cl = this . beanClassLoader ;
if ( cl = = null ) {
cl = getClass ( ) . getClassLoader ( ) ;
}
try {
Class < ? extends ObjectMapper > xmlMapper = ( Class < ? extends ObjectMapper > )
cl . loadClass ( "com.fasterxml.jackson.dataformat.xml.XmlMapper" ) ;
this . objectMapper = BeanUtils . instantiate ( xmlMapper ) ;
}
catch ( ClassNotFoundException ex ) {
throw new IllegalStateException ( "Could not instantiate XmlMapper" , ex ) ;
}
}
else {
this . objectMapper = new ObjectMapper ( ) ;
}
}
if ( this . dateFormat ! = null ) {
this . objectMapper . setDateFormat ( this . dateFormat ) ;
}
if ( this . annotationIntrospector ! = null ) {
this . objectMapper . setAnnotationIntrospector ( this . annotationIntrospector ) ;
}
if ( this . serializationInclusion ! = null ) {
this . objectMapper . setSerializationInclusion ( this . serializationInclusion ) ;
}
if ( ! this . serializers . isEmpty ( ) | | ! this . deserializers . isEmpty ( ) ) {
SimpleModule module = new SimpleModule ( ) ;
addSerializers ( module ) ;
addDeserializers ( module ) ;
this . objectMapper . registerModule ( module ) ;
}
if ( ! features . containsKey ( MapperFeature . DEFAULT_VIEW_INCLUSION ) ) {
configureFeature ( MapperFeature . DEFAULT_VIEW_INCLUSION , false ) ;
}
if ( ! features . containsKey ( DeserializationFeature . FAIL_ON_UNKNOWN_PROPERTIES ) ) {
configureFeature ( DeserializationFeature . FAIL_ON_UNKNOWN_PROPERTIES , false ) ;
}
for ( Object feature : this . features . keySet ( ) ) {
configureFeature ( feature , this . features . get ( feature ) ) ;
}
if ( this . modules ! = null ) {
// Complete list of modules given
for ( Module module : this . modules ) {
// Using Jackson 2.0+ registerModule method, not Jackson 2.2+ registerModules
this . objectMapper . registerModule ( module ) ;
}
if ( this . objectMapper ! = null ) {
this . builder . configure ( this . objectMapper ) ;
}
else {
// Combination of modules by class names specified and class presence in the classpath
if ( this . modulesToInstall ! = null ) {
for ( Class < ? extends Module > module : this . modulesToInstall ) {
this . objectMapper . registerModule ( BeanUtils . instantiate ( module ) ) ;
}
}
if ( this . findModulesViaServiceLoader ) {
// Jackson 2.2+
this . objectMapper . registerModules ( ObjectMapper . findModules ( this . beanClassLoader ) ) ;
}
else {
registerWellKnownModulesIfAvailable ( ) ;
}
}
if ( this . propertyNamingStrategy ! = null ) {
this . objectMapper . setPropertyNamingStrategy ( this . propertyNamingStrategy ) ;
}
}
@SuppressWarnings ( "unchecked" )
private < T > void addSerializers ( SimpleModule module ) {
for ( Class < ? > type : this . serializers . keySet ( ) ) {
module . addSerializer ( ( Class < ? extends T > ) type , ( JsonSerializer < T > ) this . serializers . get ( type ) ) ;
}
}
@SuppressWarnings ( "unchecked" )
private < T > void addDeserializers ( SimpleModule module ) {
for ( Class < ? > type : this . deserializers . keySet ( ) ) {
module . addDeserializer ( ( Class < T > ) type , ( JsonDeserializer < ? extends T > ) this . deserializers . get ( type ) ) ;
}
}
private void configureFeature ( Object feature , boolean enabled ) {
if ( feature instanceof JsonParser . Feature ) {
this . objectMapper . configure ( ( JsonParser . Feature ) feature , enabled ) ;
}
else if ( feature instanceof JsonGenerator . Feature ) {
this . objectMapper . configure ( ( JsonGenerator . Feature ) feature , enabled ) ;
}
else if ( feature instanceof SerializationFeature ) {
this . objectMapper . configure ( ( SerializationFeature ) feature , enabled ) ;
}
else if ( feature instanceof DeserializationFeature ) {
this . objectMapper . configure ( ( DeserializationFeature ) feature , enabled ) ;
}
else if ( feature instanceof MapperFeature ) {
this . objectMapper . configure ( ( MapperFeature ) feature , enabled ) ;
}
else {
throw new FatalBeanException ( "Unknown feature class: " + feature . getClass ( ) . getName ( ) ) ;
}
}
@SuppressWarnings ( "unchecked" )
private void registerWellKnownModulesIfAvailable ( ) {
ClassLoader cl = this . beanClassLoader ;
if ( cl = = null ) {
cl = getClass ( ) . getClassLoader ( ) ;
}
// Java 8 java.time package present?
if ( ClassUtils . isPresent ( "java.time.LocalDate" , cl ) ) {
try {
Class < ? extends Module > jsr310Module = ( Class < ? extends Module > )
cl . loadClass ( "com.fasterxml.jackson.datatype.jsr310.JSR310Module" ) ;
this . objectMapper . registerModule ( BeanUtils . instantiate ( jsr310Module ) ) ;
}
catch ( ClassNotFoundException ex ) {
// jackson-datatype-jsr310 not available
}
}
// Joda-Time present?
if ( ClassUtils . isPresent ( "org.joda.time.LocalDate" , cl ) ) {
try {
Class < ? extends Module > jodaModule = ( Class < ? extends Module > )
cl . loadClass ( "com.fasterxml.jackson.datatype.joda.JodaModule" ) ;
this . objectMapper . registerModule ( BeanUtils . instantiate ( jodaModule ) ) ;
}
catch ( ClassNotFoundException ex ) {
// jackson-datatype-joda not available
}
this . objectMapper = this . builder . build ( ) ;
}
}
@ -533,7 +351,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@@ -533,7 +351,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
@Override
public Class < ? > getObjectType ( ) {
return ( this . objectMapper ! = null ) ? this . objectMapper . getClass ( ) : null ;
return ( this . objectMapper ! = null ? this . objectMapper . getClass ( ) : null ) ;
}
@Override