Deserializing LocalDateTime with Jackson JSR310 mo

2019-02-16 08:42发布

问题:

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

回答1:

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;
    }  
}


回答2:

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]


回答3:

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.