We're migrating from Joda to Java Time. Currently we use DateTime
of Joda in our entity. AFAIK DateTime
is equivalent to two types in Java: OffsetDateTime
and ZonedDateTime
. Since we're going to persist them in DB, we're gonna use OffsetDateTime
(any comment on this?).
Now the problem is how to configure Jackson's ObjectMapper
properly.
All examples I found on the web are about local types for which Jackson's already provided de/serializer implementations (e.g. LocalDateTime
, LocalDateTimeSerializer
and LocalDateTimeDeserializer
).
I finally managed to do something like this:
public class OffsetDateTimeSerializer extends StdSerializer<OffsetDateTime> {
private final DateTimeFormatter formatter; // We need custom format!
public OffsetDateTimeSerializer(DateTimeFormatter formatter) {
super(OffsetDateTime.class);
this.formatter = formatter;
}
@Override
public void serialize(OffsetDateTime value, JsonGenerator generator, SerializerProvider provider) throws IOException {
generator.writeString(value.format(formatter));
}
}
and
public class OffsetDateTimeDeserializer extends StdDeserializer<OffsetDateTime> {
private final DateTimeFormatter formatter; // We need custom format!
public OffsetDateTimeDeserializer(DateTimeFormatter formatter) {
super(OffsetDateTime.class);
this.formatter = formatter;
}
@Override
public OffsetDateTime deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
return OffsetDateTime.parse(parser.readValueAs(String.class), formatter);
}
}
Now my question is what is the best way to configure Jackson's ObjectMapper
to de/serialize Java 8 date-time values?
UPDATE: the accepted answer does not really solve my problem (read the discussion in comments). I ended up with a little simpler code than what I proposed in the above. See my own answer as well.
You don't need to write your custom serializer and deserializer for JSR-310 types. Jackson has a custom module to handle that and will provide you with the serializer and deserializer you need.
First add the jackson-datatype-jsr310
artifact to your dependencies:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9</version>
</dependency>
Then register the JavaTimeModule
module in your ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Most JSR-310 types will be serialized using a standard ISO-8601 string representation. If you need a custom format, you can use your own serializer and deserializer implementation.
See the documentation for details.
Ok, so I ended up with the following (a little less code, no concrete classes):
private JavaTimeModule newJavaTimeModule() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(LocalDate.class, new LocalDateSerializer(DEFAULT_LOCAL_DATE_FORMATTER));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DEFAULT_LOCAL_DATE_FORMATTER));
module.addSerializer(OffsetDateTime.class, offsetDateTimeSerializer());
module.addDeserializer(OffsetDateTime.class, offsetDateTimeDeserializer());
return module;
}
private StdSerializer<OffsetDateTime> offsetDateTimeSerializer(DateTimeFormatter formatter) {
return new OffsetDateTimeSerializer(OffsetDateTimeSerializer.INSTANCE, false, formatter) {};
}
private StdDeserializer<OffsetDateTime> offsetDateTimeDeserializer(DateTimeFormatter formatter) {
return new InstantDeserializer<OffsetDateTime>(InstantDeserializer.OFFSET_DATE_TIME, formatter) {};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With