Include null Value in JSON Serialization
1. Introduction
JavaScript Object Notation (JSON) is text-based data format that is easy for humans to read and write and easy for machines to parse and generate. It is widely used for APIs to exchange data between a client and server. JSON serialization is the process of converting a Java object into a JSON string. In Java, null
is a keyword that indicates the object referring to nothing. In this example, I will demonstrate JSON null serialization with both Jackson and Gson libraries. Here are main reasons to include the null
values in Json serialization:
- Data Representation: including
null
value explicitly indicates that a value is missing or undefined, rather than omitted by mistake. - Consistent Structure: ensuring that all objects have the same structure can simplify data handling. Using
null
for missing values can help maintain consistency. - API Communication: using
null
can clarify that a field is intentionally left empty. This can prevent confusion about whether a field was forgotten or intentionally set to a blank state. - Database Operations: database
null
value can be used at queries and integrity constraints. - Schema Validation: specifying
null
can help ensure that data conforms to the expected schema withnull
value. - Backward Compatibility: using
null
allows new fields to be added without breaking existing systems that consume the data, as they can safely ignore or handle thenull
values. - Default Values:
null
can indicate a default state that needs to be populated later or a field that is optional and currently not set. - Explicit Absence: It explicitly signifies that the absence of value is acknowledged and intended, which can be important for business logic and application behavior.
2. Customer Management System
In this step, I will create a simple customer management system which has two model classes: customer
and order
. One customer may have one or more orders. The customer
class has five fields:
id
– the unique id.name
– the customer’s name, this is a required field.email
– the customer’s email address, it’s an optional field, but requiresnull
value in Json serialization.custTag
– the customer’s tag. it’s an optional field and only included when it’s notnull
.orders
– a list of orders belongs to the customer. It is an optional field.
The order
class has three members:
productName
– the order’s product name. It’s optional.quantity
– the order’s quantity.orderTag
– the optional order tag.
3. JSON Null Serialization via Jackson
The Jackson library from FasterXML is the most popular library for serializing Java objects to JSON and vice-versa. By default, it includes the null
values, however, the default behavior can be overwritten with the @JsonInclude
annotation and ObjectMapper.setSerializationInclusion
method. In this step, I will create a maven project and demonstrate the Json null serialization via a Junit test class.
3.1 Setup Maven project
In this step, I will create a pom.xml
to include the Jackson libraries.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.zheng.demo</groupId> <artifactId>jackson-null</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.17.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.17.1</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> </dependencies> </project>
Note: Include jackson-databind
and jackson-annotations
libraries.
3.2 Create Data Objects
In this step, I will create two POJO classes: Customer
and Order
based on the requirement at step 2.
Customer.java
package org.zheng.demo.data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) public class Customer implements Serializable { private static final long serialVersionUID = 5963349342478710542L; private String custTag; private String email; private int id; private String name; private List<Order> orders; public Customer() { super(); } public Customer(String name, int id) { super(); this.id = id; this.name = name; } public String getCustTag() { return custTag; } public String getEmail() { return email; } public int getId() { return id; } public String getName() { return name; } public List<Order> getOrders() { return orders; } public void setCustTag(String custTag) { this.custTag = custTag; } public void setEmail(String email) { this.email = email; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void addOrder(Order order) { if (this.orders == null) { this.orders = new ArrayList<>(); } this.orders.add(order); } public void setOrders(List<Order> orders) { this.orders = orders; } }
Note: line 9 marks @JsonInclude(JsonInclude.Include.NON_NULL)
at the class level, so only non-null values are serialized for Customer
objects.
Order.java
package org.zheng.demo.data; import com.fasterxml.jackson.annotation.JsonInclude; public class Order { @JsonInclude(JsonInclude.Include.NON_NULL) private String orderTag; private String productName; private int quantity; public Order() { super(); } public Order(int quantity, String name) { super(); this.quantity = quantity; this.productName = name; } public String getOrderTag() { return orderTag; } public String getProductName() { return productName; } public int getQuantity() { return quantity; } public void setOrderTag(String orderTag) { this.orderTag = orderTag; } public void setProductName(String name) { this.productName = name; } public void setQuantity(int quantity) { this.quantity = quantity; } }
Note: line 7 has @JsonInclude(JsonInclude.Include.NON_NULL)
at the field level, so non-null value of the orderTag
field is included when serializing the Order
objects.
3.3 Test via Jackson ObjectMapper
In this step, I will create a JacksonTest
class which has five test methods.
test_include_null_as_default
– print out theOrder
‘s JSON string and verify that Jackson libraryObjectMapper
includesnull
values in JSON as default.test_include_null_as_default_with_exclusion
– similar totest_include_null_as_default
, but theorderTag
field overrides the default setting with@JsonInclude(JsonInclude.Include.NON_NULL
.test_setSerializationInclusion_for_nonNull
– verify the default includesnull
values overwritten by theObjectMapper.setSerializationInclusion(Include.NON_NULL)
;test_annotation_for_nonNull
– TheCustomer
class declares@JsonInclude(JsonInclude.Include.NON_NULL)
at class level, sonull
values are excluded from JSON serialization.test_mixed_annotation
– verify the mixed@JsonInclude(JsonInclude.Include.NON_NULL)
atCustomer
class declaration and theOrder
‘s field declaration.
JacksonTest.java
package org.zheng.demo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.zheng.demo.data.Customer; import org.zheng.demo.data.Order; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; class JacksonTest { private Customer cust = new Customer("Zheng", 30); private ObjectMapper ob = new ObjectMapper(); private Order order = new Order(); @Test void test_annotation_for_nonNull() { cust.setEmail("test@test.com"); String jsonStr; try { jsonStr = ob.writerWithDefaultPrettyPrinter().writeValueAsString(cust); assertFalse(jsonStr.contains("null"), "Json string contains non-null due to JsonInclude.Include.NON_NULL set at class level."); System.out.println(jsonStr); Customer person2 = ob.readValue(jsonStr, Customer.class); assertEquals("Zheng", person2.getName()); assertEquals(30, person2.getId()); assertEquals("test@test.com", person2.getEmail()); } catch (JsonProcessingException e) { e.printStackTrace(); } } @Test void test_include_null_as_default() { String jsonStr; try { jsonStr = ob.writeValueAsString(order); assertTrue(jsonStr.contains("null"), "Json string contains null by Jackson default"); assertFalse(jsonStr.contains("custTag"), "set JsonInclude.Include.NON_NULL on the custTag, so won't include"); // include null element System.out.println(jsonStr); // {"productName":null,"quantity":0} Order data = ob.readValue(jsonStr, Order.class); assertNull(data.getOrderTag()); } catch (JsonProcessingException e) { e.printStackTrace(); } } @Test void test_include_null_as_default_with_exclusion() { order.setOrderTag("serialize if not null"); String jsonStr; try { jsonStr = ob.writeValueAsString(order); assertTrue(jsonStr.contains("null"), "Json string contains null by Jackson default"); assertTrue(jsonStr.contains("orderTag"), "set JsonInclude.Include.NON_NULL on the orderTag. include as it has value."); // include null element System.out.println(jsonStr); // {"orderTag":"serialize if not null","productName":null,"quantity":0} Order data = ob.readValue(jsonStr, Order.class); assertEquals("serialize if not null", data.getOrderTag()); } catch (JsonProcessingException e) { e.printStackTrace(); } } @Test void test_mixed_annotation() { cust.addOrder(order); String jsonStr; try { jsonStr = ob.writerWithDefaultPrettyPrinter().writeValueAsString(cust); assertFalse(jsonStr.contains("\"email\" : null"), "Json string contains non-null due to JsonInclude.Include.NON_NULL set at Customer class level."); assertTrue(jsonStr.contains("\"productName\" : null"), "Json string contains non-null due to JsonInclude.Include.NON_NULL set at Customer class level."); System.out.println(jsonStr); Customer person2 = ob.readValue(jsonStr, Customer.class); assertEquals("Zheng", person2.getName()); assertEquals(30, person2.getId()); } catch (JsonProcessingException e) { e.printStackTrace(); } } @Test void test_setSerializationInclusion_for_nonNull() { String jsonStr; try { ob.setSerializationInclusion(Include.NON_NULL); jsonStr = ob.writeValueAsString(order); assertFalse(jsonStr.contains("null"), "Json string contains non-null when setSerializationInclusion() is configured globally"); // only include non-null element System.out.println(jsonStr);// {"quantity":0} Order data = ob.readValue(jsonStr, Order.class); assertNull(data.getOrderTag()); } catch (JsonProcessingException e) { e.printStackTrace(); } } }
- Line 17 – creates and initializes a
cust
object from theCustomer
class. - Line18 – creates an
ObjectMapper
with default setting. - Line 19 – creates and initializes an
order
object from theOrder
class. - Line 27 – serializes the
cust
object into Json viawriteValueAsString
with default pretty format. - Line 47 – serializes the
order
object into Json viawriteValueAsString
. - Line 69 – Excludes the “
orderTag
” field as it marks with@JsonInclude(JsonInclude.Include.NON_NULL)
. - Line 122 – overwrites the
ObjectMapper
setting withob.setSerializationInclusion(Include.NON_NULL)
;
3.4 Demonstrate Json Null Serialization via Jackson
In this step, I will execute each test method and capture the output.
test_annotation_for_nonNull output
{ "email" : "test@test.com", "id" : 30, "name" : "Zheng" }
Note: serialized the non-null values as the Customer
class annotated with @JsonInclude(JsonInclude.Include.NON_NULL)
.
test_include_null_as_default output
{"productName":null,"quantity":0}
Note: the productName
is included with null
value but the orderTag
is excluded due to @JsonInclude(JsonInclude.Include.NON_NULL)
annotation.
test_include_null_as_default_with_exclusion output
{"orderTag":"serialize if not null","productName":null,"quantity":0}
Note: the productName
is included with null
value and the orderTag
is included as it is not null.
test_mixed_annotation output
{ "id" : 30, "name" : "Zheng", "orders" : [ { "productName" : null, "quantity" : 0 } ] }
Note: the order’s productName
is included with null
value. but the email
is excluded due to @JsonInclude(JsonInclude.Include.NON_NULL)
at the Customer
class level.
test_setSerializationInclusion_for_nonNull output
{"quantity":0}
Note: non-null values are serialized due to ob.setSerializationInclusion(Include.NON_NULL
).
4. JSON Null Serialization via Gson
Gson is a Java library from Google that serializes and deserializes Java Objects into their JSON representation and vice-versa. By default, Gson does not include any null
values in the JSON. I will demonstrate how to include Null values via GsonBuilder().serializeNulls()
.
4.1 Setup Maven project
In this step, I will create a pom.xml to include the Gson library.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.zheng.demo</groupId> <artifactId>gson-null</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> </dependencies> </project>
4.2 Create Data Objects
This step is similar to step 3.2 but with Gson’s @Expose
annotation which marks fields intended to expose so we can use excludeFieldsWithoutExposeAnnotation
to customize JSON fields.
Customer.java
package org.zheng.demo.data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import com.google.gson.annotations.Expose; public class Customer implements Serializable { private static final long serialVersionUID = 5963349342478710542L; private String custTag; @Expose private String email; @Expose private int id; @Expose private String name; private List<Order> orders; public Customer() { super(); } public Customer(String name, int id) { super(); this.id = id; this.name = name; } public void addOrder(Order order) { if (orders == null) { orders = new ArrayList<>(); } orders.add(order); } public String getCustTag() { return custTag; } public String getEmail() { return email; } public int getId() { return id; } public String getName() { return name; } public List<Order> getOrders() { return orders; } public void setCustTag(String custTag) { this.custTag = custTag; } public void setEmail(String email) { this.email = email; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setOrders(List<Order> orders) { this.orders = orders; } }
Note: line 15, 18 21 annotate @Expose
so these fields will be serialized when excludeFieldsWithoutExposeAnnotation
is configured.
The Order
class detail.
Order.java
package org.zheng.demo.data; public class Order { private String productName; private int quantity; public Order() { super(); } public Order(int quantity, String productName) { super(); this.quantity = quantity; this.productName = productName; } public String getProductName() { return productName; } public int getQuantity() { return quantity; } public void setProductName(String productName) { this.productName = productName; } public void setQuantity(int quantity) { this.quantity = quantity; } }
4.3 Create Gson Test
In this step, I will create a GsonTest
class with six methods to demonstrate Json null serialization via Gson and GsonBuilder libraries.
test_default_nonnull
– theGson
andGsonBuilder's
excludenull
values as default.test_serializeNulls
– verifynull
values are serialized whenserializeNulls
is used.test_serialize_null_with_Expose
– verify null values are serialized whenserializeNulls
method is used and excludes these fields not marked with the@Expose
annotation.
GsonTest.java
package org.zheng.demo; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.zheng.demo.data.Customer; import org.zheng.demo.data.Order; import com.google.gson.Gson; import com.google.gson.GsonBuilder; class GsonTest { private Customer customer = new Customer("Mary", 5); private Order order = new Order(1, null); @Test void test_default_nonnull() { // By default, Gson excludes fields with null values. String json = new Gson().toJson(order); assertFalse(json.contains("null"), "Gson default excludes null values."); System.out.println(json); // {"quantity":1} // using the GsonBuilder and setting the serializeNulls method. String jsonString = new GsonBuilder().create().toJson(customer); assertFalse(jsonString.contains("null"), "GsonBuilder default excludes null values."); System.out.println(jsonString); // {"id":5,"name":"Mary"} } @Test void test_serialize_null_with_Expose() { Gson gson = new GsonBuilder().serializeNulls().excludeFieldsWithoutExposeAnnotation().create(); customer.setCustTag("NOT_Serialized_field"); String jsonStr = gson.toJson(customer); assertFalse(jsonStr.contains("notIncludeInJson"), "not expose field not included"); assertTrue(jsonStr.contains("null"), "Json string contains null when serializeNulls() is configured"); System.out.println(jsonStr); // {"email":null,"id":5,"name":"Mary"} Customer desObj = gson.fromJson(jsonStr, Customer.class); assertNull(desObj.getCustTag()); } @Test void test_serializeNulls() { customer.addOrder(order); Gson gson = new GsonBuilder().serializeNulls().create(); String jsonString = gson.toJson(customer); assertTrue(jsonString.contains("custTag"), "not calling excludeFieldsWithoutExposeAnnotation, so ignore the @expose."); assertTrue(jsonString.contains("null"), "Json string contains null when serializeNulls() is configured"); System.out.println(jsonString); // {"custTag":null,"email":null,"id":5,"name":"Mary","orders":[{"productName":null,"quantity":1}]} } }
- Line 16, 17 – defined a
customer
andorder
objects. - Line 20 – verify the
Gson
default setting includes non-null values. - Line 22 –
toJson()
serializes a Java object into JSON string. - Line 36, 37 – verify the
GsonBuilder
withserializeNulls
andexcludeFieldsWithoutExposeAnnotation
() which includes nulls but excludes the fields without@Expose
annotation. - Line 54, 57 – verify the
GsonBuilder
withserializeNulls
() to serialize null values.
4.4 Demonstrate Json Null Serialization via Gson
In this step, I will execute each test and capture the output.
test_default_nonnull output
{"quantity":1} {"id":5,"name":"Mary"}
Note: by Gson default, only non-null values are serialized.
test_serialize_null_with_Expose output
{"email":null,"id":5,"name":"Mary"}
Note: the email
with the null
value is serialized as expected.
test_serializeNulls output
{"custTag":null,"email":null,"id":5,"name":"Mary","orders":[{"productName":null,"quantity":1}]}
Note: the null email
from customer
and null productName
from order
are serialized as expected.
5. Conclusion
Serializing JSON with null
values provides clarity and consistency. In this example, I demonstrated how to serialize JSON with null values with both Jackson and Gson open source libraries. The following table outlines the main difference at Null serialization between these two popular libraries.
Jackson | Gson | |
Open-source | active development | maintenance mode, no new features |
Default null setting | include null values as default | exclude null values as default |
Configuration | setSerializationInclusion | serializeNulls |
Annotation | @JsonInclude(JsonInclude.Include.NON_NULL) | No |
6. Download
These were two examples of maven projects which utilize both Jackson and Gson libraries for JSON null values serialization.
You can download the full source code of this example here: Include null Value in JSON Serialization