Introduction to Jackson ObjectMapper

Jackson ObjectMapper

Introduction

In the ever-evolving landscape of software development, efficient data serialization and deserialization are crucial for seamless communication between different components of a system. Jackson Object Mapper, a powerful Java library, has become a go-to tool for developers when dealing with JSON and other data formats. In this blog post, we’ll explore the fundamentals of Jackson Object Mapper and delve into its practical usage.

What is Jackson Object Mapper?

Jackson is a high-performance JSON processor for Java, providing a set of tools to work with JSON data. At its core is the Jackson Object Mapper, a module that facilitates the conversion between Java objects and JSON data, as well as other data formats like XML. It is widely used in enterprise-level applications and open-source projects due to its simplicity, versatility, and robust performance.

Getting Started

To integrate Jackson into your project, you can include the Jackson dependencies in your build tool (e.g., Maven, Gradle). Once added, you can start using the ObjectMapper class to serialize Java objects to JSON and deserialize JSON back to Java objects.

Maven Dependencies:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<properties>
<jackson.version>2.15.4</jackson.version>
</properties>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>

<!-- Jackson Annotations (Optional, for using annotations like @JsonProperty) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>

Serialization

use writeValueAsString to convert Java object to JSON string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ObjectMapper objectMapper = new ObjectMapper();

MyObject myObject = new MyObject(/* initialize your object */);

try {
// Convert Java object to JSON string
String jsonString = objectMapper.writeValueAsString(myObject);
System.out.println(jsonString);

// Convert Java object to JSON string with pretty printing
String jsonString2 = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(myObject);
System.out.println(jsonString2);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

Deserialization

1
2
3
4
5
6
7
8
String jsonString = /* JSON string from some source */;
try {
// Convert JSON string to Java object
MyObject myObject = objectMapper.readValue(jsonString, MyObject.class);
System.out.println(myObject);
} catch (JsonProcessingException e) {
e.printStackTrace();
}

Annotations for Customization:

Jackson provides a set of annotations that allow fine-grained control over the serialization and deserialization process. For example, @JsonProperty lets you specify the name of a property when serialized:

1
2
3
4
5
public class Item {
@JsonProperty("item_name")
private String name;
private long price;
}

Handling Date Formats

Date serialization and deserialization often require specific formats. Jackson allows you to configure date formats globally or on a per-field basis:

1
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));

Handling Java 8 Date/Time Types

With the introduction of Java 8, new date and time types like LocalDate, LocalDateTime, and ZonedDateTime have become popular. Jackson provides a module called jackson-datatype-jsr310 to handle these types:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.1</version>
</dependency>

To use the module, you can register it with the ObjectMapper:

1
2
3
4
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
String jsonString = objectMapper.writeValueAsString(item);
System.out.println(jsonString);

output

1
2
3
4
5
{
"name" : "book",
"price" : 20,
"createdDate" : 1625119200.000000000
}

To serialize and deserialize Java 8 date/time types in a readable format, you can configure the ObjectMapper as follows:

1
2
3
4
5
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

SerializationFeature.WRITE_DATES_WITH_ZONE_ID: When enabled, the date/time values are serialized with the time zone ID, such as “Asia/Shanghai”.

DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE: When disabled, the date/time values are deserialized without adjusting to the context time zone. This is useful when you want to preserve the original time zone from the Json string.

Handling List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ObjectMapper objectMapper = new ObjectMapper();

List<Item> items = List.of(
new Item().setName("book").setPrice(20),
new Item().setName("pen").setPrice(2)
);

try {
String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(items);
System.out.println(jsonString);

List<Item> deserializedItems = objectMapper.readValue(jsonString, new TypeReference<List<Item>>(){});
deserializedItems.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}

In this example, The TypeReference<List<Item>>(){} is used to specify the type of the list.

If you just juse List.class as the type, you will get a list of LinkedHashMap. and results in a ClassCastException when you try to cast it to List<Item>.

Handling Polymorphic Types:

When working with polymorphic types, Jackson supports annotations like @JsonTypeInfo and @JsonSubTypes to handle the serialization and deserialization of class hierarchies:

1
2
3
4
5
6
7
8
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@Type(value = Dog.class, name = "dog"),
@Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
// common fields and methods
}

Conclusion

Jackson Object Mapper simplifies the complex task of data serialization and deserialization in Java applications. Its flexibility, performance, and extensive features make it an essential tool for developers working with JSON and other data formats. By understanding the basics and exploring advanced features, developers can harness the full potential of Jackson to streamline data processing in their projects.