Is it a bug in jackson-datatype-jsr310 deserialize

2019-03-03 12:12发布

问题:

I know that's presumptuous to image found a bug in a library used every day by thousands of developpers. So I think the answer to my title question is "NO !!!", but ...

I have an object containing a date that I receive from my front end (JS), and I store it into a MongoDB database. I use Spring to get this object (with a REST Controller), and Spring to perform persistance (with a MongoDBRepository). My computer is configured with a CEST clock, so GMT+2 (UTC +0200).

The date in my POJO is stored in a LocalDateTime.

Here is my object :

class Test{
  LocalDateTime when;
  String data;
  // getter setters...
}

The following unit test show that Spring (which use jackson-jsr310) fill my LocalDateTime with an UTC Date Time.

mockMvc.perform(post("/test")
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .content("{\"when\":\"2017-03-31T14:20:28.000Z\",\"data\":\"toto\"}")).andExpect(status().isOk());

List<com.robopec.models.Test> tests =  testRepository.findAll();
Assert.assertEquals(14, tests.get(0).getWhen().getHour());

We can see in the jackson source code LocalDateTimeDeserializer.java line 74 :

 return LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC);

But when I save in my database, spring use spring-data-commons to convert my LocalDateTime to a Date before storing the date in the database. We can read in spring-data-commons/../Jsr310Converters.java this :

public static enum LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {
        INSTANCE;
        @Override
        public Date convert(LocalDateTime source) {
            return source == null ? null : Date.from(source.atZone(systemDefault()).toInstant());
        }
    }

So, spring-data JSR310 Converters interpret a localdatetime as an instant in the default system zone.

The problem is that when my front end send "2017-04-03T20:00:00Z", the REST controller store it in a LocalDateTime with the following time : 20:00:00. And when the mongo-data converter convert it into a date, the resulting time is 20:00:00+0200 (because my computer is in CEST time zone).

My conclusion is that I shouldn't store my date in a LocalDateTime but rather in a Date (java.util) or in an Instant.

But, is there a bug in one of the converters ?

回答1:

If I remember correctly, the latest version of the Java driver for mongoDB still use java.util.Date to store dates, so using the Java 8 time api can be a bit of a hassle.

In one project I work on, I switched from Joda Datetime to the Java 8 time a few months ago. I couldn't get my way around with LocalDateTime, ZonedDateTime and so on, so I decided to go with Instant and it worked fine. Just remember to use the ISO8601 Zulu notation for your dates ("2017-03-31T14:20:28.000Z"), which is already what you're doing apparently.