Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjectMapper configuation for Java 8 Time API

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.

like image 424
Rad Avatar asked Apr 23 '18 10:04

Rad


2 Answers

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.

like image 157
cassiomolin Avatar answered Sep 22 '22 06:09

cassiomolin


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) {};
}
like image 41
Rad Avatar answered Sep 19 '22 06:09

Rad