java.time和JPA
来自包java.time
的LocalDateTime
的类别为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..
}
我的答案看起来非常直接而且毫无价值,但它更多的是把事情集中在一起并进行总结。
首先,这个问题没有“金子弹”解决方案。东西肯定要改变,我看到3个选项或3层的替代品:
删除
Serializable
接口。在所有实体上放置Serializable
并不是一个“好习惯”。仅当您要将它的实例用作分离对象时才需要:When and why JPA entities should implement Serializable interface?。使用时间戳类型而不是LocalDateTime。在我看来,这是等价的:默认情况下
https://github.com/javaee/jpa-spec/issues/63
即时,LocalDateTime,OffsetDateTime和ZonedDateTime地图为 时间戳值。您可以使用@TeMPOraL标记这些 类型之一的属性,以指定用于坚持 该属性的不同策略。
- 如果两个第一选项不为你工作,然后(我敢肯定,你知道该怎么做) - 禁止这种警告
@SuppressWarnings("squid:S3437")
。
我不太明白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所接受)和背部。
我的问题不是如何在JPA中使用LocalDateTime,而是如何解决使用可序列化但也基于值的类的矛盾。请仔细阅读我的问题;)这不会回答它 – itsme
您编写问题的方式很难理解。可序列化是一种标记,您不必实现任何方法。它只是告诉这个类的一个实例可以通过RMI传输或保存在文件系统中。没有义务。没有限制,你不应该使用LocalDateTime作为JPA实体的一个字段,我已经发布了一个工作示例。 LocalDateTime可以转换,你现在有一个示例代码。 – dimirsen
谢谢你的回答,但在我的问题中没有提到LocalDateTime的转换不起作用。它是关于序列化值一般疑问句基础,为什么LocalDateTime既有的,但同时它不应该像 – itsme
为什么你会认为基于价值的课程不应该被序列化?当然,他们可以序列化。这就是为什么它实现了Serializable。 –
好吧,我们现在有这个故事,目前我们只是'@SuppressWarnings(“squid:S3437”)',现在有一个关于dev-list的评论(我会试着去挖掘它)它说*这*可能*禁止这些基于价值的类*被移动到基于价值*类型* – Eugene
@JBNizet这是LocalDateTime真的很奇怪。它也是一个基于值的类。如果您查看oracle文档,您会发现以下有关基于值的类的声明:https:// docs。oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html 一个程序可能产生不可预测的结果,如果它试图两个引用区分的基于值的类[相等的值... ]序列化或任何其他身份敏感机制。这种使用可能会产生不可预测的影响,应予以避免。 – itsme