Jackson deserialize elasticsearch long as LocalDateTime with Java 8 Jackson deserialize elasticsearch long as LocalDateTime with Java 8 elasticsearch elasticsearch

Jackson deserialize elasticsearch long as LocalDateTime with Java 8


To build LocalDateTime from milliseconds from the epoch of 1970-01-01T00:00:00Z we need a time zone. In version 2.9.9 it throws exception when milliseconds appears:

raw timestamp (1563448935000) not allowed for java.time.LocalDateTime: need additional information such as an offset or time-zone (see class Javadocs)

But we can implement our deserialiser which will try to do this with default time zone. Example implementation could look like below:

class MillisOrLocalDateTimeDeserializer extends LocalDateTimeDeserializer {    public MillisOrLocalDateTimeDeserializer() {        super(DateTimeFormatter.ISO_LOCAL_DATE_TIME);    }    @Override    public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {        if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {            long value = parser.getValueAsLong();            Instant instant = Instant.ofEpochMilli(value);            return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);        }        return super.deserialize(parser, context);    }}

ZoneOffset.UTC is used. In your case you can provide yours or use system default. Example usage:

import com.fasterxml.jackson.core.JsonParser;import com.fasterxml.jackson.core.JsonToken;import com.fasterxml.jackson.databind.DeserializationContext;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;import java.io.IOException;import java.time.Instant;import java.time.LocalDateTime;import java.time.ZoneOffset;import java.time.format.DateTimeFormatter;public class JsonApp {    public static void main(String[] args) throws Exception {        JavaTimeModule javaTimeModule = new JavaTimeModule();        // override default        javaTimeModule.addDeserializer(LocalDateTime.class, new MillisOrLocalDateTimeDeserializer());        ObjectMapper mapper = new ObjectMapper();        mapper.registerModule(javaTimeModule);        String json = "{\"created\":1563448935000}";        System.out.println(mapper.readValue(json, Created.class));    }}class Created {    private LocalDateTime created;    // getters, setters, toString}

Above code prints:

Created{created=2019-07-18T11:22:15}

EDIT: Using Jackson 2.9.0, because of this issue the code provided will not be invoked since findAndRegisterModules which is called AFTER registering the customized module will override it. Removing that call will make the full scenario work. If above will not work for your version, you need to debug default implementation and find a reason.


Use Instant as a Jackson field type for dates. This simplifies everything!All you will need is only register module: https://github.com/FasterXML/jackson-modules-java8