java.time 和 JPA
java.time and JPA
类 因为包 java.time
中的 LocalDateTime
是 value based classes。如果我有一个实体使用这样的对象作为字段,我 运行 进入以下 "problem":
基于值的 classes 不应被序列化。但是,JPA 实体必须实现接口 Serializable。这个悖论的解决方案是什么?有人不应该将 LocalDateTime 用作 JPA 实体的字段吗?改用日期?这会令人不满意。
这个问题是 Sonar 规则 squid:S3437
因此项目中有很多错误,因为我们从 Date 更改为 LocalDateTime ...
由于基于价值的 class 用法,解决方案不合规:
@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..
}
我不太明白你的数据库从 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 接受)并返回。
我的回答看似很直接,毫无价值,但更多的是为了整理和总结。
首先,这个问题没有 "golden bullet" 解决方案。有些东西肯定必须改变,我看到 3 个选项或 3 个备选方案:
删除Serializable
接口。将 Serializable
放在所有实体上并不是 "good practice"。仅当您要将它的实例用作分离对象时才需要它:When and why JPA entities should implement Serializable interface?.
使用时间戳类型而不是 LocalDateTime。在我看来是等价的:
https://github.com/javaee/jpa-spec/issues/63
Instant, LocalDateTime, OffsetDateTime, and ZonedDateTime map as
timestamp values by default. You may mark a property of one of these
types with @TeMPOraL to specify a different strategy for persisting
that property.
- 如果第一个选项都不适合您,那么(我很确定,您知道该怎么做)- 取消此警告
@SuppressWarnings("squid:S3437")
。
类 因为包 java.time
中的 LocalDateTime
是 value based classes。如果我有一个实体使用这样的对象作为字段,我 运行 进入以下 "problem":
基于值的 classes 不应被序列化。但是,JPA 实体必须实现接口 Serializable。这个悖论的解决方案是什么?有人不应该将 LocalDateTime 用作 JPA 实体的字段吗?改用日期?这会令人不满意。
这个问题是 Sonar 规则 squid:S3437
因此项目中有很多错误,因为我们从 Date 更改为 LocalDateTime ...
由于基于价值的 class 用法,解决方案不合规:
@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..
}
我不太明白你的数据库从 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 接受)并返回。
我的回答看似很直接,毫无价值,但更多的是为了整理和总结。
首先,这个问题没有 "golden bullet" 解决方案。有些东西肯定必须改变,我看到 3 个选项或 3 个备选方案:
删除
Serializable
接口。将Serializable
放在所有实体上并不是 "good practice"。仅当您要将它的实例用作分离对象时才需要它:When and why JPA entities should implement Serializable interface?.使用时间戳类型而不是 LocalDateTime。在我看来是等价的:
https://github.com/javaee/jpa-spec/issues/63
Instant, LocalDateTime, OffsetDateTime, and ZonedDateTime map as timestamp values by default. You may mark a property of one of these types with @TeMPOraL to specify a different strategy for persisting that property.
- 如果第一个选项都不适合您,那么(我很确定,您知道该怎么做)- 取消此警告
@SuppressWarnings("squid:S3437")
。