Customize Jackson JSON Mapper in Spring Boot Customize Jackson JSON Mapper in Spring Boot

Page content

In this tutorial, we’ll learn how to customize the default Jackson JSON Mapper in Spring Boot Web Application with various Jackson configurations.

Overview

Spring MVC uses the Jackson JSON ObjectMapper as the default HttpMessageConverters in your Spring Boot web application, which does mainly two things:-

  1. Map the Java Object to JSON Response when you return the Object from GET request method like this:-

    @GetMapping
    public List<User> getAllUsers()
    

    The process of converting the Java Object to JSON is known as Marshalling or Serialization

  2. Map the JSON to Java Object when you add a @RequestBody argument in POST request method like this:-

    @PostMapping
    public Long createUser(@RequestBody User user)
    

    The process of converting the JSON to Java Object is known as Unmarshalling or Deserialization

Customize Default ObjectMapper

In this section, we’ll see how to customize the auto-configured default ObjectMapper implicitly used by Spring Boot.

Using Application Properties

Spring Boot auto-configures the default ObjectMapper based on the configurations provided in property files i.e. application.yml or application.properties file. Spring Boot also auto-registers the Jackson modules in ObjectMapper, if they are available in the classpath.

It is recommended to use the auto-configured ObjectMapper and customize the behavior by turning on/off the Jackson serialization and deserialization features using the property file. Set the Jackson property to true or false to enable or disable the feature respectively.

Most of the customization use cases can be achieved with this approach. Here is the complete list of Jackson serialization, deserialization, and mapper configuration properties, which you can use:-

application.yml
spring: jackson: default-property-inclusion: use_defaults/always/non-null/non-empty/non-absent/non-default serialization: CLOSE_CLOSEABLE: true/false EAGER_SERIALIZER_FETCH: true/false FAIL_ON_EMPTY_BEANS: true/false FAIL_ON_SELF_REFERENCES: true/false FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS: true/false FLUSH_AFTER_WRITE_VALUE: true/false INDENT_OUTPUT: true/false ORDER_MAP_ENTRIES_BY_KEYS: true/false USE_EQUALITY_FOR_OBJECT_ID: true/false WRAP_EXCEPTIONS: true/false WRAP_ROOT_VALUE: true/false WRITE_BIGDECIMAL_AS_PLAIN: true/false WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS: true/false WRITE_DATES_AS_TIMESTAMPS: true/false WRITE_DATES_WITH_ZONE_ID: true/false WRITE_DATE_KEYS_AS_TIMESTAMPS: true/false WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS: true/false WRITE_DURATIONS_AS_TIMESTAMPS: true/false WRITE_EMPTY_JSON_ARRAYS: true/false WRITE_ENUMS_USING_INDEX: true/false WRITE_ENUMS_USING_TO_STRING: true/false WRITE_ENUM_KEYS_USING_INDEX: true/false WRITE_NULL_MAP_VALUES: true/false WRITE_SELF_REFERENCES_AS_NULL: true/false WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED: true/false deserialization: ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT: true/false ACCEPT_EMPTY_STRING_AS_NULL_OBJECT: true/false ACCEPT_FLOAT_AS_INT: true/false ACCEPT_SINGLE_VALUE_AS_ARRAY: true/false ADJUST_DATES_TO_CONTEXT_TIME_ZONE: true/false EAGER_DESERIALIZER_FETCH: true/false FAIL_ON_IGNORED_PROPERTIES: true/false FAIL_ON_INVALID_SUBTYPE: true/false FAIL_ON_MISSING_CREATOR_PROPERTIES: true/false FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY: true/false FAIL_ON_NULL_CREATOR_PROPERTIES: true/false FAIL_ON_NULL_FOR_PRIMITIVES: true/false FAIL_ON_NUMBERS_FOR_ENUMS: true/false FAIL_ON_READING_DUP_TREE_KEY: true/false FAIL_ON_TRAILING_TOKENS: true/false FAIL_ON_UNKNOWN_PROPERTIES: true/false FAIL_ON_UNRESOLVED_OBJECT_IDS: true/false READ_DATE_TIMESTAMPS_AS_NANOSECONDS: true/false READ_ENUMS_USING_TO_STRING: true/false READ_UNKNOWN_ENUM_VALUES_AS_NULL: true/false READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE: true/false UNWRAP_ROOT_VALUE: true/false UNWRAP_SINGLE_VALUE_ARRAYS: true/false USE_BIG_DECIMAL_FOR_FLOATS: true/false USE_BIG_INTEGER_FOR_INTS: true/false USE_JAVA_ARRAY_FOR_JSON_ARRAY: true/false USE_LONG_FOR_INTS: true/false WRAP_EXCEPTIONS: true/false mapper: ACCEPT_CASE_INSENSITIVE_PROPERTIES: true/false ACCEPT_CASE_INSENSITIVE_ENUMS: true/false ACCEPT_CASE_INSENSITIVE_VALUES: true/false ALLOW_COERCION_OF_SCALARS: true/false ALLOW_EXPLICIT_PROPERTY_RENAMING: true/false ALLOW_FINAL_FIELDS_AS_MUTATORS: true/false ALLOW_VOID_VALUED_PROPERTIES: true/false AUTO_DETECT_CREATORS: true/false AUTO_DETECT_FIELDS: true/false AUTO_DETECT_GETTERS: true/false AUTO_DETECT_IS_GETTERS: true/false AUTO_DETECT_SETTERS: true/false BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES: true/false CAN_OVERRIDE_ACCESS_MODIFIERS: true/false DEFAULT_VIEW_INCLUSION: true/false IGNORE_DUPLICATE_MODULE_REGISTRATIONS: true/false IGNORE_MERGE_FOR_UNMERGEABLE: true/false INFER_PROPERTY_MUTATORS: true/false INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES: true/false INFER_BUILDER_TYPE_BINDINGS: true/false OVERRIDE_PUBLIC_ACCESS_MODIFIERS: true/false PROPAGATE_TRANSIENT_MARKER: true/false REQUIRE_SETTERS_FOR_GETTERS: true/false SORT_PROPERTIES_ALPHABETICALLY: true/false SORT_CREATOR_PROPERTIES_FIRST: true/false USE_STATIC_TYPING: true/false USE_BASE_TYPE_AS_DEFAULT_IMPL: true/false USE_GETTERS_AS_SETTERS: true/false USE_WRAPPER_NAME_AS_PROPERTY_NAME: true/false USE_STD_BEAN_NAMING: true/false

You can also refer to the Spring Boot official documentation for Jackson configurations.

Please note that the spring boot configuration supports Relaxed Binding which means properties can be in uppercase or lowercase i.e. spring.jackson.serialization.INDENT_OUTPUT and spring.jackson.serialization.indent_output both are valid.

Also Read JSON API Request and Response customization using Jackson


Using Jackson2ObjectMapperBuilderCustomizer

By default, Spring boot auto-configure Jackson2ObjectMapperBuilder bean and use this builder to auto-configure ObjectMapper (or XmlMapper for Jackson XML converter) instance.

You can customize the default behavior of Jackson2ObjectMapperBuilder by defining a custom Jackson2ObjectMapperBuilderCustomizer bean. Spring boot will use this custom builder to build ObjectMapper and XmlMapper.

@Configuration
public class CustomJacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
                .featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
                .featuresToEnable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                .failOnUnknownProperties(false)
                .featuresToDisable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .indentOutput(true)
                .modules(new JavaTimeModule());
    }
}

Using Custom ObjectMapper

If you just want to customize the default ObjectMapper and not all the Jackson mappers created by Jackson2ObjectMapperBuilder builder then follow this approach:-

@Configuration
public class CustomJacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        return builder.build().setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(SerializationFeature.INDENT_OUTPUT, true)
                .registerModule(new JavaTimeModule());
    }
}

Overwrite Default ObjectMapper

If you don’t want to rely on spring boot auto configuration and would like to have complete control over the Jackson ObjectMapper instance then overwrite the default ObjectMapper by providing a custom bean.

Using Jackson2ObjectMapperBuilder

When you define a new custom Jackson2ObjectMapperBuilder bean, it disables all auto-configurations of ObjectMapper and XmlMapper and uses your custom builder to build them. An example of a custom object builder is as follows:-

@Configuration
public class CustomJacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder()
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .featuresToEnable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                .failOnUnknownProperties(false)
                .featuresToDisable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .indentOutput(true)
                .modules(new JavaTimeModule());
    }
}

Using Custom ObjectMapper

If you just want to overwrite the default ObjectMapper and not all the Jackson mappers created by Jackson2ObjectMapperBuilder builder then follow this approach:-

@Configuration
public class CustomJacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(SerializationFeature.INDENT_OUTPUT, true);
    }
}

Conclusion

In this article, we learned how to -

  1. Override the default behavior of Jackson JSON Mapper using application properties, defining a custom bean of Jackson2ObjectMapperBuilder or ObjectMapper.
  2. Overwrite the default behavior of Jackson JSON Mapper by defining a custom bean of Jackson2ObjectMapperBuilder or ObjectMapper.

If we want to customize all Jackson mappers i.e. ObjectMapper and XmlMapper, then define a custom Jackson2ObjectMapperBuilder bean. In case, we only want to customize Jackson ObjectMapper for JSON, then define a custom ObjectMapper bean.

We can use Jackson MapperFeature, DeserializationFeature, and SerializationFeature properties to customize mapper, deserialization, and serialization behavior respectively.

Find the source code for the examples in this article on GitHub

Thanks for Reading!