2017-04-03 61 views
0

我知道這對圖像很冒昧,在數千個開發人員每天使用的庫中發現了一個錯誤。所以我認爲我的標題問題的答案是「NO !!!」,但是...這是jackson-datatype-jsr310解串器中的錯誤嗎?

我有一個對象,包含從我的前端(JS)收到的日期,並將其存儲到MongoDB中數據庫。我使用Spring來獲取此對象(使用REST控制器),並使用Spring來執行持久性(使用MongoDBRepository)。我的電腦配置了CEST時鐘,所以GMT + 2(UTC +0200)。

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

這是我的目標:

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

下面的單元測試表明,春季(其中使用傑克遜 - jsr310)填補我的LocalDateTime與UTC日期時間。

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

但是當我保存在我的數據庫,彈簧使用彈簧數據公地到存儲在我的LocalDateTime轉換爲日期數據庫中的日期。 我們可以在這個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()); 
     } 
    } 

所以,彈簧數據JSR310轉換器解釋一個localdatetime作爲默認的系統區域瞬間。

問題是,當我的前端發送「2017-04-03T20:00:00Z」時,REST控制器將其存儲在LocalDateTime中,時間爲:20:00:00。當mongo數據轉換器將其轉換爲日期時,結果時間爲20:00:00 + 0200(因爲我的電腦處於CEST時區)。

我的結論是我不應該將我的日期存儲在LocalDateTime中,而是存儲在Date(java.util)或Instant中。

但是,是否有一個轉換器中的錯誤?

+0

您是否使用POJO樣本建議的LocalDateTime或LocalDate?你使用的是哪個數據庫? Spring Data的哪個版本? –

+0

你說得對,我正在使用LocalDateTime(我將編輯我的文章)。數據庫是一個MongoDB數據庫。我使用spring-boot-starter-data-mongodb版本1.5.1和jackson-datatype-jsr310:2.8.6 –

回答

1

如果我沒有記錯的話,mongoDB的Java驅動的最新版本仍然使用java.util.Date來存儲日期,所以使用Java 8的api可能會有點麻煩。

在我工作的一個項目中,我在幾個月前從Joda Datetime切換到了Java 8。我無法繞過LocalDateTime,ZonedDateTime等等,所以我決定去Instant,它工作得很好。只記得你的日期使用ISO8601祖魯語符號(「2017-03-31T14:20:28.000Z」),這已經是你明顯做的了。

+0

這也是我的結論。 –