这是jackson-datatype-jsr310解串器中的错误吗?

时间:2017-04-03 20:52:06

标签: java spring-data jsr310

我知道,图像的冒昧发现每天都有成千上万的开发人员在库中发现了一个错误。所以我认为我的标题问题的答案是" NO !!!",但是......

我有一个对象,其中包含我从前端(JS)收到的日期,并将其存储到MongoDB数据库中。我使用Spring来获取这个对象(使用REST控制器),使用Spring来执行持久性(使用MongoDBRepository)。我的电脑配置了CEST时钟,因此GMT + 2(UTC +0200)。

我的POJO中的日期存储在LocalDateTime中。

这是我的目标:

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

以下单元测试显示Spring(使用jackson-jsr310)用UTC日期时间填充我的LocalDateTime。

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());

我们可以在杰克逊源代码LocalDateTimeDeserializer.java第74行看到:

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

但是当我保存在我的数据库中时,spring会在将日期存储到数据库之前使用spring-data-commons将我的LocalDateTime转换为Date。 我们可以在spring-data-commons/../Jsr310Converters.java中阅读:

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

因此,spring-data JSR310转换器将localdatetime解释为默认系统区域中的瞬间。

问题在于,当我的前端发送&#34; 2017-04-03T20:00:00Z&#34;时,REST控制器将其存储在LocalDateTime中,时间如下:20:00:00。当mongo-data转换器将其转换为日期时,结果时间为20:00:00 + 0200(因为我的计算机处于CEST时区)。

我的结论是,我不应该将我的日期存储在LocalDateTime中,而应该存储在Date(java.util)或Instant中。

但是,其中一个转换器是否存在错误?

1 个答案:

答案 0 :(得分:3)

如果我没记错的话,mongoDB的最新版本的Java驱动程序仍然使用java.util.Date来存储日期,因此使用Java 8时间api可能会有点麻烦。

在我工作的一个项目中,几个月前我从Joda Datetime切换到Java 8时间。我无法使用LocalDateTime,ZonedDateTime等等,所以我决定选择Instant并且它运行正常。请记住在您的日期使用ISO8601 Zulu表示法(“2017-03-31T14:20:28.000Z”),这已经是您正在做的事情。