Introduction to Jackson ObjectMapper

Jackson ObjectMapper

Introduction

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 Dependency

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.18.2</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 ObjectMapper.writeValueAsString(Object) method to convert Java object to JSON string. com.fasterxml.jackson.databind.ObjectMapper is the main class to perform serialization and deserialization in Jackson.

Entity

1
2
3
4
public class Item {
private String name;
private int price;
}

Convert Java object to JSON string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ObjectMapper objectMapper = new ObjectMapper();

Item item = new Item();
item.setName("book");
item.setPrice(20);

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

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

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

output:

1
2
3
4
5
6
{"name":"book","price":20}
=====================================
{
"name" : "book",
"price" : 20
}

Deserialization

use ObjectMapper.readValue(String, Class) method to convert JSON string to Java object.

1
2
3
4
5
6
7
8
String jsonString = /* JSON string from some source */;
try {
// Convert JSON string to Java object
Item deserializedItem = objectMapper.readValue(jsonString, Item.class);
System.out.println(deserializedItem);
} 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
  • @JsonInclude allows you to exclude null or empty values from the output
  • @JsonPropertyOrder lets you specify the order of properties in the output
  • @JsonIgnore excludes a property from serialization and deserialization
  • @JsonManagedReference and @JsonBackReference manage bidirectional relationships

Example:

1
2
3
4
5
6
7
8
9
10
@JsonPropertyOrder({"item_name", "price"})
public class Item {
@JsonProperty("item_name")
private String name;

private int price;

@JsonIgnore
private String summary;
}

Sample output:

1
2
3
4
{
"item_name" : "book",
"price" : 20
}

@JsonIgnoreProperties - Annotation that can be used to either suppress serialization of properties (during serialization), or ignore processing of JSON properties read (during deserialization).

1
2
3
4
5
6
7
8
Example:
```java
// to prevent specified fields from being serialized or deserialized
// (i.e. not include in JSON output; or being set even if they were included)
@JsonIgnoreProperties({ "internalId", "secretKey" })

// To ignore any unknown properties in JSON input without exception:
@JsonIgnoreProperties(ignoreUnknown=true)

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.18.2</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.

References