Learn to fix the error ‘Java 8 date/time type not supported by default‘ while serializing and deserializing Java 8 Date time classes using Jackson.
1. Problem
The error occurs when we serialize a Java object or deserialize JSON to POJO, and the POJO contains new Java 8 date time classes such as LocalDate, LocalTime, LocalDateTime etc.
For example, the following Employee class has LocalDate type field.
public class Employee {
private Long id;
private String name;
private LocalDate dateOfBirth;
}
When we serialize an instance of this class, we get the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: Java 8 date/time type `java.time.LocalDate` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.howtodoinjava.core.objectToMap.Employee["dateOfBirth"])
at com.fasterxml.jackson.databind.ObjectMapper ._convert(ObjectMapper.java:4393)
at com.fasterxml.jackson.databind.ObjectMapper .convertValue(ObjectMapper.java:4324)
at com.howtodoinjava.core.objectToMap .ObjectToMapUsingJackson.main(ObjectToMapUsingJackson.java:25)
2. Solution
We must add support to new Java 8 classes in two steps to fix this error.
First, add the latest version of com.fasterxml.jackson.datatype:jackson-datatype-jsr310 Maven dependency.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.4</version>
</dependency>
Second, register the module JavaTimeModule
either with ObjectMapper or JsonMapper based on what you are using.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
//or
JsonMapper jsonMapper = new JsonMapper();
jsonMapper.registerModule(new JavaTimeModule());
After registering the JavaTimeModule, the above error will go away.
3. With Hibernate 6
The above solution may not work if you are facing this issue due to Hibernate 6 that serializes the objects using FormatMapper instances, and the default is JacksonJsonFormatMapper. The JacksonJsonFormatMapper basically uses a Jackson ObjectMapper instance constructed without any additional options.
To fix the issue, we need to create a custom instance of FormatMapper and assign it through a new property hibernate.type.json_format_mapper.
spring.jpa.properties.hibernate.type.json_format_mapper=com.howtodoinjava.CustomJacksonJsonFormatMapper
And then create the mapper implementation as follows:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.hibernate.type.FormatMapper;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.jackson.JacksonJsonFormatMapper;
public class JacksonJsonFormatMapperCustom implements FormatMapper {
private final FormatMapper delegate;
public JacksonJsonFormatMapperCustom() {
ObjectMapper objectMapper = createObjectMapper();
delegate = new JacksonJsonFormatMapper(objectMapper);
}
private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
@Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
return delegate.fromString(charSequence, javaType, wrapperOptions);
}
@Override
public <T> String toString(T t, JavaType<T> javaType, WrapperOptions wrapperOptions) {
return delegate.toString(t, javaType, wrapperOptions);
}
}
Happy Learning !!
Comments