Zurück zum Blog

Add Support for Java 8 Date & Time API to Jackson Serialized REST Web Services

Jackson may fail to deserialize Java 8 Date and Time API types such as LocalDate in REST clients unless support for these types is registered explicitly. The jackson-datatype-jsr310 module adds the missing JSR-310 handling. In Spring environments, this requires ObjectMapper configuration unless Spring Boot performs the registration automatically.

#Java#Java 8#Jackson#REST
Kaffeetasse als Symbolbild für Java
#Java

When you are building REST web services using the Java 8 JDK, you might want to use the new Date & Time API to define temporal fields in your entity classes. For example, you might define the following simple User entity with the three fields username, fullname, and dateOfBirth:

import java.time.LocalDate;

public class User {
    private String username;
    private String fullname;
    private LocalDate dateOfBirth;

    // getters + setters...
}

An instance of this entity could be serialized as a JSON string in your REST service as follows:

{
    username: "jane.doe",
    fullname: "Jane Doe",
    dateOfBirth: [
        1986,
        10,
        06
    ]
}

When you try to consume such a web service with the Jackson mapper, for instance using Spring’s RestTemplate classes, you will experience the following exception:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class java.time.LocalDate]: can not instantiate from JSON object (need to add/enable type information?)

The problem here is that Jackson does not support the Java 8 Date & Time API out of the box, so you have to add this support yourself. But rest assured, adding this support is simple, as there is already a support library available from FasterXML: jackson-datatype-jsr310. To enable support for these new data types, you simply have to add the jackson-datatype-jsr310 support library to your classpath, for example with Maven:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.4.0</version>
</dependency>

Update: As Khaled correctly points out in the comments, you also need to explicitly tell the Jackson ObjectMapper to include support for JSR 310. In a Spring environment this could be achieved by the following bean definition (example courtesy of Khaled):

@Bean(name = "OBJECT_MAPPER_BEAN")
public ObjectMapper jsonObjectMapper() {
    return Jackson2ObjectMapperBuilder.json()
            .serializationInclusion(JsonInclude.Include.NON_NULL) // Don’t include null values
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) //ISODate
            .modules(new JSR310Module())
            .build();
}

If you’re like me, working with Spring Boot, you don’t need any explicit configuration, since this registration is automatically done for you by Spring Boot. But of course in a different environment, the Jackson ObjectMapper needs to be specifically set up.