Deserializing LocalDateTime with Jackson JSR310 module
Asked Answered
N

3

28

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...

Nitid answered 10/4, 2015 at 22:24 Comment(3)
I think it may work if you switch to ZoneDateTime.Mariko
@AlexeyGavrilov, that actually works, thanks. If you submit it as answer I'll mark it as correct. Still find it weird that setting the dateFormat on the objectmapper itself has absolutely no effect with regards to serialization/deserialization but using ZonedDateTime is easy enough :-)Nitid
The ObjectMapper's DateFormat is only for the built-in java.util.Date support, I guess. Passing a value with a time-zone indication to a LocalDateTime is a smell- Instant or OffsetDateTime (or even ZonedDateTime) is more applicable.Heavyfooted
D
46

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;
    }  
}
Dice answered 5/11, 2015 at 14:10 Comment(3)
I believe this answer to be more appropriate since it demonstrates how to setup the ObjectMapper to automatically and correctly handle deserialization. This is required if you do not manually use the ObjectMapper intsance to read incomming strings, but instead work through things such as RestTemplateFancie
Hmmm. I get this exception when I tried this: java.lang.IllegalAccessError: tried to access method com.fasterxml.jackson.databind.ser.std.StdSerializer.&lt;init&gt;&#40;Ljava/lang/Class&#59;&#41;V from class com.fasterxml.jackson.datatype.jsr310.JavaTimeModuleAgger
could you take a look #44918521 ? Is it similar? If possible answer please.Variate
M
6

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]
Mariko answered 11/4, 2015 at 16:33 Comment(2)
Note that JSR310Module has been deprecated, use JavaTimeModule instead.Fancie
You can find the new module here: github.com/FasterXML/jackson-modules-java8.Emblements
T
2

Hibernate 4, Spring 4 - REST WS, Client - Spring Boot 1.5.2. In my case I used in Entity ZonedDateTime class to map Timestamp in database. Hibernate as well as Spring Boot REST works fine. I must only add libraries into pom file:

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
    </dependency>

So I suppose, that converter is implemented inside Spring for LocalDateTime as well.The jackson.version is the latest one.

Tombaugh answered 28/7, 2017 at 14:17 Comment(2)
The OP mentioned that they are already using the Jackson JSR 310 module (otherwise the JSR310Module class wouldn't be available).Brazen
Yes, of course, but I didn't anything more to do. Object Mapper is not needed, neither registering module.Tombaugh

© 2022 - 2025 — McMap. All rights reserved.