Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing LocalDateTime with Jackson JSR310 module

I'm using the library described the Jackson Datatype JSR310 page but I'm still having difficulty getting it to work.

I have configured the following bean:

@Bean
@Primary
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JSR310Module());
    return mapper;
}

When I call my REST API the date format output is yyyy-MM-dd'T'HH:ss.SSSSSS, e.g. 2015-04-11T00:10:38.905847. This gets handled by my AngularJS code just fine.

When I want to submit something to the REST API the date is posted as yyyy-MM-dd'T'HH:mm:ss.SSS'Z', e.g. 2015-04-09T08:30:00.000Z

Jackson keeps complaining about the 'Z' at the end. If I look at the LocalDateTimeDeserializer in the documentation it uses the DateTimeFormatter.ISO_LOCAL_DATE_TIME which boils to ISO_LOCAL_DATE'T'ISO_LOCAL_TIME and it mentions it has no override zone.

So I figured I should set the DateFormat on the ObjectMapper I'm creating:

@Bean
@Primary
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JSR310Module());
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
    return mapper;
}

But this does nothing. I changed it to something simple like yyyy-MM-dd but the serialized date remained in the previous format and the deserialization isn't affected either.

What am I doing wrong here to get this to work? The date format in my JavaScript code is, as far as I know the ISO 8601 format...

like image 724
Mekswoll Avatar asked Apr 10 '15 22:04

Mekswoll


2 Answers

It's not necessary to write your own serializer. It's enough use the default one, but making an instance with another format (the time_zone one) so that the exceeding part is just cut:

new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME)

In my case I've got a contextResolver like this to achieve at configuration level:

@Service 
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {  
    private final ObjectMapper mapper;

    public ObjectMapperContextResolver() {
        mapper = new ObjectMapper();
        JavaTimeModule javaTimeModule=new JavaTimeModule();
        // Hack time module to allow 'Z' at the end of string (i.e. javascript json's) 
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME));
        mapper.registerModule(javaTimeModule);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }  
}
like image 73
user1299153 Avatar answered Oct 04 '22 03:10

user1299153


For now LocalDateTimeDeserializer does not seem to respect the date format set for the object mapper.

To make it work you can override LocalDateTimeDeserializer or switch to use ZoneDateTime which handles the 'Z' char at the end.

Here is an example:

public class Java8DateFormat {
    public static void main(String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JSR310Module());
        // mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));

        final String date = mapper.writeValueAsString(new Date());
        System.out.println(date);
        System.out.println(mapper.readValue(date, ZonedDateTime.class));
    }
}

Output:

"2015-04-11T18:24:47.815Z"
2015-04-11T18:24:47.815Z[GMT]
like image 39
Alexey Gavrilov Avatar answered Oct 04 '22 04:10

Alexey Gavrilov