2017-12-18 314 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