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.
Thank you. But if you use custom attributes for com.fasterxml.jackson.databind.ObjectMapper, you need to explicitly tell it to support JSR310 (after adding the dependency of course)
Here is the factory @Bean method I use:
@Bean(name = OBJECT_MAPPER_BEAN)
public ObjectMapper jsonObjectMapper() {
return Jackson2ObjectMapperBuilder.json()
.serializationInclusion(Include.NON_NULL) // Don’t include null values
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) //ISODate
.modules(new JSR310Module())
.build();
}
Regards
Hi Khaled, thank you for pointing this out! I updated the article accordingly. As a user of Spring Boot, I never noticed that there might be anything more to set up than adding a mere project dependency. But of course in a different setup you have to configure the ObjectMapper explicitly.
Javascript does not like the [yy, mm, dd] format. Any suggestions about how to change it to a timestamp?
I’m getting this error
for my
private LocalDate bday;
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (START_OBJECT), expected START_ARRAY: Expected array or string.
I get the following error:
http://stackoverflow.com/questions/38330074/restful-service-in-spring-configuration-with-jackson-datatype-jsr310
Any help appreciated.