25

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

Vikas Prasad
  • 3,163
  • 5
  • 28
  • 39
Mekswoll
  • 1,355
  • 3
  • 15
  • 35
  • 2
    I think it may work if you switch to ZoneDateTime. – Alexey Gavrilov Apr 11 '15 at 08:37
  • @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 :-) – Mekswoll Apr 11 '15 at 11:59
  • 1
    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. – araqnid Nov 08 '15 at 21:26

3 Answers3

45

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;
    }  
}
helencrump
  • 1,351
  • 1
  • 18
  • 27
user1299153
  • 663
  • 8
  • 10
  • 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 `RestTemplate` – demaniak May 30 '16 at 11:13
  • Hmmm. I get this exception when I tried this: java.lang.IllegalAccessError: tried to access method com.fasterxml.jackson.databind.ser.std.StdSerializer.<init>(Ljava/lang/Class;)V from class com.fasterxml.jackson.datatype.jsr310.JavaTimeModule – rakehell May 31 '16 at 23:54
  • could you take a look https://stackoverflow.com/questions/44918021/how-to-use-some-jackson-deserializer-in-own-custom-deserializer ? Is it similar? If possible answer please. – Marek Urbanowicz Jul 05 '17 at 06:34
5

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]
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
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.

hariprasad
  • 555
  • 11
  • 20
  • The OP mentioned that they are already using the Jackson JSR 310 module (otherwise the `JSR310Module` class wouldn't be available). – cassiomolin Jul 28 '17 at 14:25
  • Yes, of course, but I didn't anything more to do. Object Mapper is not needed, neither registering module. – hariprasad Jul 28 '17 at 15:49