Null values arise a lot in software development, and proper handling of null
values can be turned into a science in and of itself. Jackson is the de facto library for serialization and deserialization of Java objects - and a common scenario pertains to serializing objects that have null
fields.
In this short tutorial, we'll take a look at how you can ignore null fields when serializing a POJO with Jackson.
Changing the ObjectMapper Settings
Jackson's ObjectMapper is the central API that maps objects to serialized values. Naturally, you can adjust and customize the way it works through various flags, one of which is:
objectMapper.setSerializationInclusion(Include.NON_NULL);
When serializing with this mapper, properties will only be included if they're non-null.
This sets the flag globally for any object being serialized with the objectMapper
instance. If you're working with Spring Boot, and the ObjectMapper it's relying on isn't exposed, you can alter the flag in the application.properties
file:
spring.jackson.default-property-inclusion = non_null
Or, if you're using application.yml
:
spring:
jackson:
default-property-inclusion: non_null
Note: Older versions of Spring used spring.jackson.serialization-inclusion=non_null
instead of spring.jackson.default-property-inclusion=non_null
.
Alternatively, you can peel back replace the default ObjectMapper
instance by registering a new @Primary
@Bean
, named objectMapper()
, which overrides the default implementation and allows full customization over the instance that'll be used by default when serializing and deserializing:
@Bean
@Primary
public ObjectMapper objectMapper() {
return new ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
This @Bean
should go into any file that's annotated with the @Configuration
annotation, and is oftentimes situated either in a specialized configuration class or the main class of the Spring Boot application.
Changing the Jackson2ObjectMapperBuilder Instance
Spring uses the HttpMessageConverters
to convert between HTTP messages and objects. The default converters are the ObjectMapper
and XmlMapper
instances instantiated via the Jackson2ObjectMapperBuilder
.
Instead of manually providing the primary ObjectMapper
(replacing the one provided by the builder), you can instruct Spring on how to build the object mapper instead. This allows Spring to do its high-level configurations without you tampering with the lower-level objects, while still customizing the way it works. Additionally, you can also customize the XmlMapper
this way in one go.
To customize the builder, you register a new @Bean
of Jackson2ObjectMapperBuilderCustomizer
type, which customizes and returns the builder:
@Bean
public Jackson2ObjectMapperBuilderCustomizer customBuilder() {
return builder -> {
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
}
}
@JsonInclude Annotation
On the other end of the spectrum, we can use annotations, as a low-code alternative! Annotations can be applied at the class-level or method-level:
@JsonInclude(JsonInclude.Include.NON_NULL)
This allows you to customize only certain classes, instead of the global behavior of the object mapper.
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Note: As of Jackson 2.0, the annotation's value is JsonInclude.Include.NON_NULL
. For earlier versions, use include=JsonSerialize.Inclusion.NON_NULL
.
@JsonInclude on Class-Level
When you apply @JsonInclude
at class-level, the annotation extends to all of the getters and setters:
@Entity(name="property")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Property implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private String id;
@Column(name="transaction_type")
private TransactionType transactionType;
@Column(name="property_type")
private PropertyType propertyType;
// Constructor, getters, setters, toString(), etc.
}
Any given field that has a null
value won't be serialized.
@JsonInclude on Method-Level
Alternatively, you can apply the annotation at method-level as the most granular option:
@Entity(name="property")
public class Property implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private String id;
@Column(name="transaction_type")
@JsonInclude(JsonInclude.Include.NON_NULL)
private TransactionType transactionType;
@Column(name="property_type")
private PropertyType propertyType;
// Constructor, getters, setters, toString(), etc.
}
In this snippet - the annotation is only applied to the TransactionType
field.
Conclusion
In this guide, you've learned how to ignore null fields in Jackson, with Java and Spring Boot. This can be achieved globally by replacing the underlying implicit ObjectMapper
instance and customizing the behavior of the new primary bean you register.
Alternatively, you can customize the Jackson2ObjectMapperBuilder
that builds the ObjectMapper
for your application instead of replacing the already built one. For a low-code solution - you can change the spring.jackson.default-property-inclusion
property in your properties files.
Finally - you can use the @JsonInclude
annotation on class-level or method-level.