2017-12-18 311 views
6

來自包java.timeLocalDateTime的類別爲value based classes。如果我有一個使用這樣的對象作爲字段的實體,我會遇到以下「問題」: 基於值的類不應被序列化。但是,JPA實體必須實現Serializable接口。這個悖論的解決方案是什麼?不應該有人使用LocalDateTime作爲JPA實體的字段嗎?改用日期?這將是不令人滿意的。java.time和JPA

這個問題是一個聲納規則squid:S3437,因此也有很多項目的錯誤的,因爲我們從日期到LocalDateTime改變......

不兼容的解決方案由於基於值類的用法:

@Entity 
public class MyEntity implements Serializable{ 
    @Column 
    private String id; // This is fine 
    @Column 
    private LocalDateTime updated; // This is not ok, as LocalDateTime is a value based class 
    @Column 
    private Date created; // This however is fine.. 
} 
+4

爲什麼你會認爲基於價值的課程不應該被序列化?當然,他們可以序列化。這就是爲什麼它實現了Serializable。 –

+0

好吧,我們現在有這個故事,目前我們只是'@SuppressWarnings(「squid:S3437」)',現在有一個關於dev-list的評論(我會試着去挖掘它)它說*這*可能*禁止這些基於價值的類*被移動到基於價值*類型* – Eugene

+0

@JBNizet這是LocalDateTime真的很奇怪。它也是一個基於值的類。如果您查看oracle文檔,您會發現以下有關基於值的類的聲明:https:// docs。oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html 一個程序可能產生不可預測的結果,如果它試圖兩個引用區分的基於值的類[相等的值... ]序列化或任何其他身份敏感機制。這種使用可能會產生不可預測的影響,應予以避免。 – itsme

回答

2

我的答案看起來非常直接而且毫無價值,但它更多的是把事情集中在一起並進行總結。

首先,這個問題沒有「金子彈」解決方案。東西肯定要改變,我看到3個選項或3層的替代品:

  1. 刪除Serializable接口。在所有實體上放置Serializable並不是一個「好習慣」。僅當您要將它的實例用作分離對象時才需要:When and why JPA entities should implement Serializable interface?

  2. 使用時間戳類型而不是LocalDateTime。在我看來,這是等價的:默認情況下

https://github.com/javaee/jpa-spec/issues/63

即時,LocalDateTime,OffsetDateTime和ZonedDateTime地圖爲 時間戳值。您可以使用@TeMPOraL標記這些 類型之一的屬性,以指定用於堅持 該屬性的不同策略。

  • 如果兩個第一選項不爲你工作,然後(我敢肯定,你知道該怎麼做) - 禁止這種警告@SuppressWarnings("squid:S3437")
  • +1

    完成我紀念你的答案的解決方案,因爲它可以用來解決該「問題」。然而,當我解決問題的時候,我感覺不到解脫,原因是:爲什麼LocalDateTime都是基於值和Serializable的。這似乎很奇怪...... – itsme

    +1

    @itsme同樣適用於JDK-9'immutable'集合,他們被宣佈爲值類型的文檔中,但他們實現'Serializable' – Eugene

    +0

    @Eugene很好的瞭解。你知道這背後的推理嗎? – itsme

    1

    我不太明白DB從jpa接受的內容。當我處理的Postgres,我使用自定義的轉換器:

    import javax.persistence.AttributeConverter; 
    import javax.persistence.Converter; 
    import java.sql.Timestamp; 
    import java.time.LocalDateTime; 
    
    @Converter(autoApply = true) 
    public class LocalDateTimePersistenceConverter implements AttributeConverter<LocalDateTime, Timestamp> { 
    
        @Override 
        public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) { 
         return (locDateTime == null ? null : Timestamp.valueOf(locDateTime)); 
        } 
    
        @Override 
        public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) { 
         return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime()); 
        } 
    } 
    

    我使用這種方式:

    @Column(name = "create_date") 
    @Convert(converter = LocalDateTimePersistenceConverter.class) 
    private LocalDateTime createDate; 
    

    你看,我在這裏轉換LocalDateTime到時間戳(Postgres所接受)和背部。

    +0

    我的問題不是如何在JPA中使用LocalDateTime,而是如何解決使用可序列化但也基於值的類的矛盾。請仔細閱讀我的問題;)這不會回答它 – itsme

    +0

    您編寫問題的方式很難理解。可序列化是一種標記,您不必實現任何方法。它只是告訴這個類的一個實例可以通過RMI傳輸或保存在文件系統中。沒有義務。沒有限制,你不應該使用LocalDateTime作爲JPA實體的一個字段,我已經發布了一個工作示例。 LocalDateTime可以轉換,你現在有一個示例代碼。 – dimirsen

    +0

    謝謝你的回答,但在我的問題中沒有提到LocalDateTime的轉換不起作用。它是關於序列化<->值一般疑問句基礎,爲什麼LocalDateTime既有的,但同時它不應該像 – itsme