Customize Jackson JSON Mapper in Spring Boot
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:-
-
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
-
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 -
- Override the default behavior of Jackson JSON Mapper using application properties, defining a custom bean of
Jackson2ObjectMapperBuilder
orObjectMapper
. - Overwrite the default behavior of Jackson JSON Mapper by defining a custom bean of
Jackson2ObjectMapperBuilder
orObjectMapper
.
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!