JSON
Jackson
Date Format
Data Mapping
Serialization

Date format Mapping to JSON Jackson

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In the domain of Java application development, seamlessly converting Java objects into their JSON representation and vice versa is a common requirement. One of the most popular libraries for this serialization and deserialization process is the Jackson library. Among the many things that Jackson can handle, date formatting can often be a source of confusion. In this article, we'll delve into date format mapping using Jackson, exploring how to properly serialize and deserialize dates, and how to ensure consistent formats across your application.

Java Date and JSON

Java's legacy Date type and more modern classes from the java.time package can be challenging when it comes to serialization. This is because JSON does not have a native Date type; dates are typically represented as strings. Thus, converting Java dates to and from JSON requires an explicit format specification.

Basic Date Serialization and Deserialization

Here's a simple example demonstrating how Jackson handles java.util.Date by default:

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import java.util.Date;
3
4public class DateExample {
5    public static void main(String[] args) throws Exception {
6        ObjectMapper mapper = new ObjectMapper();
7        Date now = new Date();
8
9        // Serialize
10        String jsonDate = mapper.writeValueAsString(now);
11        System.out.println("Serialized Date: " + jsonDate);
12
13        // Deserialize
14        Date parsedDate = mapper.readValue(jsonDate, Date.class);
15        System.out.println("Deserialized Date: " + parsedDate);
16    }
17}

By default, Jackson uses the timestamp format (milliseconds since epoch) for java.util.Date. This may not always align with requirements that expect date strings formatted in a human-readable way.

Custom Date Formats

Using SimpleDateFormat

To customize the date format, you can make use of @JsonFormat annotation with SimpleDateFormat. Consider an entity class:

java
1import com.fasterxml.jackson.annotation.JsonFormat;
2import com.fasterxml.jackson.databind.ObjectMapper;
3import java.util.Date;
4
5public class User {
6    public String name;
7
8    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss")
9    public Date birthday;
10}
11
12public class CustomFormatExample {
13    public static void main(String[] args) throws Exception {
14        ObjectMapper mapper = new ObjectMapper();
15        User user = new User();
16        user.name = "John Doe";
17        user.birthday = new Date();
18
19        // Serialize
20        String json = mapper.writeValueAsString(user);
21        System.out.println("Serialized User: " + json);
22
23        // Deserialize
24        User deserializedUser = mapper.readValue(json, User.class);
25        System.out.println("Deserialized User Birthday: " + deserializedUser.birthday);
26    }
27}

Here, the @JsonFormat specifies that the Date should be serialized and deserialized using the dd-MM-yyyy HH:mm:ss format.

Registering Custom Formats Globally

While annotations are useful for individual fields, you might want to set a custom format for all dates in your application. This can be achieved by configuring the ObjectMapper:

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
5import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
6
7import java.text.SimpleDateFormat;
8import java.time.LocalDate;
9import java.time.format.DateTimeFormatter;
10
11public class GlobalCustomFormatExample {
12    public static void main(String[] args) throws Exception {
13        String format = "yyyy-MM-dd";
14        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
15
16        ObjectMapper mapper = new ObjectMapper();
17        mapper.registerModule(new JavaTimeModule());
18        mapper.setDateFormat(new SimpleDateFormat(format));
19        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
20
21        // For Java 8 Date and Time API
22        JavaTimeModule module = new JavaTimeModule();
23        module.addSerializer(LocalDate.class, new LocalDateSerializer(formatter));
24        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(formatter));
25        mapper.registerModule(module);
26
27        LocalDate date = LocalDate.now();
28
29        // Serialize
30        String jsonDate = mapper.writeValueAsString(date);
31        System.out.println("Serialized LocalDate: " + jsonDate);
32
33        // Deserialize
34        LocalDate parsedDate = mapper.readValue(jsonDate, LocalDate.class);
35        System.out.println("Deserialized LocalDate: " + parsedDate);
36    }
37}

In the above example, we configure the ObjectMapper not only to use a global date format for java.util.Date but also to handle java.time.LocalDate using a custom module configuration.

Key Points and Summary

In summary, Jackson provides flexible tools for managing date formats in JSON. Here’s a table summarizing the key points discussed:

FeatureMethodDescription
Default Date SerializationDefault timestamp formatDates serialized as milliseconds since epoch.
Custom Field Format@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "format-pattern")Specify date format per field using annotations.
Global Date Formatmapper.setDateFormat(new SimpleDateFormat("format-pattern"))Configure global date format for java.util.Date.
Java 8 Date/Time APIUse JavaTimeModule with custom LocalDateSerializer and LocalDateDeserializerSerialize Java 8 date types using custom format.

Conclusion

Date processing and formatting can be a challenge when dealing with JSON serialization and deserialization. By leveraging Jackson's rich annotations and configuration capabilities, you can ensure that your application handles dates in a consistent and readable manner. By choosing between field-level annotations and global mapper configuration, you strike a balance between flexibility and simplicity, tailoring the solution best fit for your project's needs.


Course illustration
Course illustration

All Rights Reserved.