Jackson vs Gson: A Deep Dive
This is a tutorial about Jackson vs Gson. Specifically, we will do a quick comparison of the libraries Gson and Jackson for serialization of a Java object to its JSON representation and deserialization of JSON string back to an equivalent Java object. We will talk about the benefits of each and see which library to use when.
1. Maven Dependencies
Firstly, let’s grab the maven dependencies and add to the classpath before we start working on this tutorial.
1.1. Gson
In the following code snippet, we’ll have a look at the maven dependency for Gson.
Gson Maven Dependencies
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency>
The latest version of the gson library is available here.
1.2. Jackson
The following code snippet shows the maven dependency for Jackson.
Jackson Maven Dependencies
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.0</version> </dependency>
To get the latest version of the jackson library, click here.
2. Model Classes
We’ll be using the following entity classes for demonstrating serialization and deserialization operations with Gson & Jackson.
Employee.java
public class Employee {
private int id;
private String name;
private Date date;
private List<Task> tasks;
// default constructor
// parametrized constructor
// getters , setters
}
Task.java
public class Task {
private int id;
private List<String> tags;
// default constructor
// parametrized constructor
// getters , setters
}
Let’s define a method to get an instance of the Employee class to be used throughout this tutorial.
getEmployee()
private static Employee getEmployee() {
Task task1 = new Task(1, Arrays.asList("Java", "Python", "Go"));
Task task2 = new Task(2, Arrays.asList("OAuth", "OIDC", "SAML"));
Employee employee = new Employee(1, "Andy",
Arrays.asList(task1, task2), new Date());
return employee;
}
3. Serialization
Serialization is the process of converting a Java object to its JSON representation. Let’s see a serialization example using the libraries Gson and Jackson and note the differences.
3.1. Gson
Let’s begin with a simple serialization example using the Gson library.
Serialization With Gson
private static Gson gson = new GsonBuilder()
.setPrettyPrinting().create();
public String entityToJson(Employee employee) {
String jsonString = gson.toJson(employee);
System.out.println("[GSON] Employee As JSON String: "
+ jsonString + "\n");
return jsonString;
}
3.2. Jackson
In this section, we will use the Jackson library to demonstrate a serialization operation.
Serialization With Jackson
public String entityToJson(Employee employee) {
String jsonString = null;
try {
jsonString = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(employee);
System.out.println("[JACKSON] Employee As JSON String: "
+ jsonString + "\n");
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonString;
}
Serialization Output
[GSON] Employee As JSON String: {
"id": 1,
"name": "Andy",
"date": "Jul 4, 2020, 8:43:58 PM",
"tasks": [
{
"id": 1,
"tags": [
"Java",
"Python",
"Go"
]
},
{
"id": 2,
"tags": [
"OAuth",
"OIDC",
"SAML"
]
}
]
}
[JACKSON] Employee As JSON String: {
"id" : 1,
"name" : "Andy",
"date" : 1593875638646,
"tasks" : [ {
"id" : 1,
"tags" : [ "Java", "Python", "Go" ]
}, {
"id" : 2,
"tags" : [ "OAuth", "OIDC", "SAML" ]
} ]
}
The points to be noted from the above examples are:
- We used the
new GsonBuilder().setPrettyPrinting().create()statement to create aGsoninstance enabled with pretty printing. - In Jackson, the
objectMapper.writerWithDefaultPrettyPrinter()statement provides anObjectWriterfor pretty printing. - The Jackson
ObjectMapperby default serializes theDateobject as alongepoch value. Contrarily, Gson by default serializesDateas a string.
4. Deserialization
Deserialization is the process of converting a JSON string back to its POJO instance.
We will use the JSON string output from the previous serialization example to demonstrate the following deserialization operations.
4.1. Gson
Let’s see an example to run through the standard Gson deserialization process.
Deserialization With Gson
public void jsonToEntity(String employeeJSON) {
Employee employee = gson.fromJson(employeeJSON, Employee.class);
System.out.println("[GSON] Employee: " + employee);
}
4.2. Jackson
Next, let’s take a look at the standard behavior of the Jackson API for deserialization.
Deserialization With Jackson
public void jsonToEntity(String employeeJSON) {
Employee employee = null;
try {
employee = objectMapper.readValue(employeeJSON, Employee.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("[JACKSON] Employee: " + employee);
}
Deserialization Output
[GSON] Employee Employee [id=1, name=Andy, date=Sat Jul 04 20:47:16 IST 2020, tasks=[Task [id=1,tags=[Java, Python, Go]], Task [id=2,tags=[OAuth, OIDC, SAML]]]] [JACKSON] Employee Employee [id=1, name=Andy, date=Sat Jul 04 20:47:16 IST 2020, tasks=[Task [id=1, tags=[Java, Python, Go]], Task [id=2, tags=[OAuth, OIDC, SAML]]]]
The Deserialization operation prints exactly the same Java object for both Gson and Jackson libraries.
The points to be noted from the above examples are:
- For either of the libraries, the property names in the JSON object must correlate with the Java entity field names. If the names do not match, the behavior is as follows:
- (Gson) : The fields are evaluated to
null. - (Jackson) : An
UnrecognizedPropertyExceptionis thrown.
- (Gson) : The fields are evaluated to
- As per the Javadoc of the class
GsonBuilder, theDateserialization & deserialization operations ignore the time-zone information. Therefore, any such time-zone information present in the JSON object shall be ignored.
5. Custom Serialization
Often, it is required to override the default behavior of a library for serialization. In this section, we’ll see how to create and use a custom JSON serializer.
5.1. Gson
Let’s define a custom serializer that modifies the name of the properties in the target JSON string. Also, we’ll alter the Date representation by using a custom SimpleDateFormat instance.
CustomGSONSerializer.java
public class CustomGSONSerializer implements JsonSerializer {
private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy");
@Override
public JsonElement serialize(Employee employee, Type typeOfSrc,
JsonSerializationContext context) {
JsonObject employeeDetails = new JsonObject();
JsonObject employeeJSONObj = new JsonObject();
employeeJSONObj.addProperty("<id>Employee</id>",
employee.getId());
employeeJSONObj.addProperty("<name>Employee</name>",
employee.getName());
employeeJSONObj.addProperty("<tasks>Employee</tasks>",
String.join(":", employee.getTasks().get(0).getTags()));
employeeJSONObj.addProperty("<date>Employee</date>",
sdf.format(employee.getDate()));
employeeDetails.add("employeeDetails", employeeJSONObj);
return employeeDetails;
}
}
The next step is to register our custom serializer with the GsonBuilder for the appropriate Type. Also, we’ll add the configuration to disable HTML escaping and serialize the HTML characters as is.
Custom Serialization With Gson
public String customSerializer(Employee employee) {
Gson customGson = gson.newBuilder().disableHtmlEscaping()
.registerTypeAdapter(Employee.class, new CustomGSONSerializer()).create();
String jsonString = customGson.toJson(employee);
System.out.println("[GSON] Custom Serializer: " + jsonString + "\n");
return jsonString;
}
Finally, as shown above, we create the Gson instance and invoke the usual toJson method to start serialization.
5.2. Jackson
Next, let’s create a custom serializer for the Jackson ObjectMapper with the same customizations as done in the CustomGSONSerializer in the previous section.
CustomJacksonSerializer.java
public class CustomJacksonSerializer extends StdSerializer {
private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy");
private static final long serialVersionUID = 1L;
public CustomJacksonSerializer() {
this(null);
}
public CustomJacksonSerializer(Class clazz) {
super(clazz);
}
@Override
public void serialize(Employee employee, JsonGenerator jsonGenerator,
SerializerProvider serializer) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeObjectFieldStart("employeeDetails");
jsonGenerator.writeNumberField("<id>Employee</id>",
employee.getId());
jsonGenerator.writeStringField("<name>Employee</name>",
employee.getName());
jsonGenerator.writeStringField("<tasks>Employee</tasks>",
String.join(":", employee.getTasks().get(0).getTags()));
jsonGenerator.writeObjectField("<date>Employee</date>",
sdf.format(employee.getDate()));
jsonGenerator.writeEndObject();
}
}
The following code describes how to register our own serializer with the ObjectMapperand use it for JSON serialization operations.
Custom Serialization With Jackson
public String customSerializer(Employee employee) {
ObjectMapper customObjMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule(
"CustomJacksonSerializer", new Version(1, 0, 0, null, null, null));
simpleModule.addSerializer(Employee.class,
new CustomJacksonSerializer());
customObjMapper.registerModule(simpleModule);
String employeeJSON = null;
try {
employeeJSON = customObjMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(employee);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("[JACKSON] Custom Serializer Employee: "
+ employeeJSON + "\n");
return employeeJSON;
}
Let’s see the output of the execution of the previous two examples.
Custom Serialization Output
[GSON] Custom Serializer Employee: {
"employeeDetails": {
"<id>Employee</id>": 1,
"<name>Employee</name>": "Andy",
"<tasks>Employee</tasks>": "Java:Python:Go",
"<date>Employee</date>": "04-07-20"
}
}
[JACKSON] Custom Serializer Employee: {
"employeeDetails" : {
"<id>Employee</id>" : 1,
"<name>Employee</name>" : "Andy",
"<tasks>Employee</tasks>" : "Java:Python:Go",
"<date>Employee</date>" : "04-07-20"
}
}
A few points to be noted from the above output are:
- New/modified property names introduced in the JSON string by using our own serializer.
Dateobject is now serialized based on the customSimpleDateFormatprovided.
6. Custom Deserialization
There might be scenarios where we might also have to override the default deserialization behavior.
In this section, we will define our custom deserializers, register them with their libraries, and use them for deserialization operations.
6.1. Gson
The following class CustomGSONDeSerializer attempts to parse a date by using a SimpleDateFormat object. It’ll also handle the “<>” tags in the input JSON string.
Note: The input JSON string in this example is the same as the output from the custom serialization operation in the previous section.
CustomGSONDeSerializer.java
public class CustomGSONDeSerializer implements JsonDeserializer {
private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy");
@Override
public Employee deserialize(JsonElement jsonElement, Type typeOfSrc,
JsonDeserializationContext context) throws JsonParseException {
Employee employee = new Employee();
JsonObject jsonObject = jsonElement.getAsJsonObject()
.get("employeeDetails").getAsJsonObject();
int empId = jsonObject.get("<id>Employee</id>").getAsInt();
employee.setId(empId);
employee.setName(jsonObject.get("<name>Employee</name>").getAsString());
try {
employee.setDate(sdf.parse(jsonObject.get(
"<date>Employee</date>").getAsString()));
} catch (ParseException e) {
e.printStackTrace();
}
return employee;
}
}
Next, let’s register our custom deserializer with the GsonBuilder for the appropriate Type.
Note: When reading an input JSON with “<>” tags, it is not required to configure the GsonBuilder with disableHtmlEscaping(), unlike custom serialization.
Lastly, the usual fromJson method is invoked to begin the deserialization operation.
Custom Deserialization With Gson
public void customDeSerializer(String employeeJSON) {
Gson customGson = gson.newBuilder().registerTypeAdapter
(Employee.class, new CustomGSONDeSerializer()).create();
Employee employee = customGson.fromJson(employeeJSON, Employee.class);
System.out.println("[GSON] Custom DeSerializer Employee: "
+ employee + "\n");
}
6.2. Jackson
In this section, we’ll create a custom deserializer for the ObjectMapper to modify its standard behaviour. The customizations are similar to the ones defined in the CustomGSONDeSerializer class.
CustomJacksonDeserializer.java
public class CustomJacksonDeserializer extends StdDeserializer {
private static final long serialVersionUID = 1L;
public CustomJacksonDeserializer() {
this(null);
}
public CustomJacksonDeserializer(Class clazz) {
super(clazz);
}
@Override
public Employee deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
Employee employee = new Employee();
JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
JsonNode empDetailsNode = jsonNode.get("employeeDetails");
int empId = empDetailsNode.get("<id>Employee</id>").asInt();
employee.setId(empId);
employee.setName(empDetailsNode.get(
"<name>Employee</name>").asText());
return employee;
}
}
The following code shows how to register the custom deserializer with the ObjectMapper and use it for JSON deserialization operations.
Custom Deserialization With Jackson
public void customDeSerializer(String employeeJSON) {
ObjectMapper customObjMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("CustomJacksonDeserializer",
new Version(1, 0, 0, null, null, null));
simpleModule.addDeserializer(Employee.class, new CustomJacksonDeserializer());
customObjMapper.registerModule(simpleModule);
Employee employee = null;
try {
employee = customObjMapper.readValue(employeeJSON, Employee.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("[JACKSON] Custom DeSerializer Employee : "
+ employee + "\n");
}
Let’s have a look at the output of the custom deserialization operation using Gson and Jackson libraries.
Custom Deserialization Output
[GSON] Custom DeSerializer Employee: Employee [id=1, name=Andy, date=Sun Jul 05 00:00:00 IST 2020, tasks=null] [JACKSON] Custom DeSerializer Employee : Employee [id=1, name=Andy, date=null, tasks=null]
7. Annotations
The Gson library provides a limited set of annotations (@Expose, @Until, @Since, @SerializedName, @JsonAdapter). However, the Jackson library has extensive support for annotations.
In this section, we will discuss the @Expose annotation from the Gson library and the @JsonIgnore annotation from the Jackson API.
7.1. Gson
GsonBuilderprovides a configuration to exclude certain fields during serialization and deserialization operations.
In order to do so, the properties which we want to expose and not exclude should be marked with @Expose annotation as shown below.
Product.java
public class Product {
@Expose
private int id;
@Expose
private String name;
@Expose
private String type;
private boolean launched;
Next, we create the Gson instance by calling the method excludeFieldsWithoutExposeAnnotation() on the GsonBulilder.
Also, note the use of serializeNulls() method. This overrides the default behaviour of Gson to ignore null values during serialization.
In other words, we force Gson to serialize properties with null values.
Gson Configuration For @Expose
public void ignoreAndSerialize(Product product) {
Gson customGson = gson.newBuilder()
.excludeFieldsWithoutExposeAnnotation()
.serializeNulls().create();
System.out.println("[GSON] Ignore And Serialize: "
+ customGson.toJson(product));
}
7.2. Jackson
The @JsonIgnoreannotation is similar to the @Expose annotation. It is used to mark a property to be ignored from being serialized.
Unlike GsonBuilder, no additional configuration is required to work with this annotation.
Product.java
public class Product {
private int id;
private String name;
private String type;
@JsonIgnore
private boolean launched;
Serialization Using Annotations Ouput
[GSON] Ignore And Serialize: {
"id": 1,
"name": "Television",
"type": "Electronic"
}
[JACKSON] Ignore And Serialize: {
"id" : 1,
"name" : "Television",
"type" : "Electronic"
}
Some observations from the above output are:
- When using Gson the field
launchedis not marked with@Exposeand hence is excluded from serialization. - In the case of Jackson, the
launchedproperty is annotated with@JsonIgnore. Therefore, it is ignored for serialization.
8. Summary
To summarise let’s see some noticeable difference between the two libraries.

- The Gson library is designed for scenarios where you do not have access to the source code for adding annotations.
- Also, it provides extensive support for Java Generics.
- The
toJsonand thefromJsonmethods from the Gson library throw either aJsonSyntaxExceptionor aJsonIOExceptionwhich are unchecked exceptions (a subclass ofRuntimeException).
Contrarily:
- The Jackson API provides a rich support for annotation-based configuration.
- It is the default library for serialization and deserialization operations in the Spring Boot framework.
- The
readValueandwriteValuemethods of theObjectMapperclass throw checked exceptions (a subclass ofIOExceptionandException).
To conclude, both the libraries are quite similar and are excellent options for processing JSON objects, pretty simple to use and really well documented.
9. Download the source code
All the code examples provided in this tutorial are available in a Maven project and should be easy to import and run.
You can download the full source code of this example here: Jackson vs Gson: A Deep Dive
