java.time и JPA
Классы как LocalDateTime
из пакета java.time
являются основанными на значении классами. Если у меня есть объект, использующий такой объект как поле, я сталкиваюсь со следующей "проблемой": классы, основанные на значениях, не должны сериализоваться. Однако сущность JPA должна реализовать интерфейс Serializable. Каково решение этого парадокса? Не должен ли кто-то использовать LocalDateTime как поле сущности JPA? Использовать дату вместо? Это было бы неудовлетворительно.
Эта проблема является правилом сонара squid:S3437
и поэтому в проекте много ошибок, так как мы изменили с Date на 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..
}
2 ответа
Мой ответ может показаться довольно прямым и бесполезным, но это больше для того, чтобы собрать вещи и подвести итог.
Во-первых, это то, что не существует "золотой пули" решения этой проблемы. Что-то определенно должно быть изменено, и я вижу 3 варианта или 3 альтернативы:
Удалить
Serializable
интерфейс. Это не "хорошая практика"Serializable
на всех сущностях. Это необходимо только в том случае, если вы собираетесь использовать его экземпляры как отдельные объекты: когда и почему сущности JPA должны реализовывать интерфейс Serializable?,Используйте тип Timestamp вместо LocalDateTime. Мне кажется, что это эквивалентно:
https://github.com/javaee/jpa-spec/issues/63
Мгновенные, LocalDateTime, OffsetDateTime и ZonedDateTime сопоставляются как значения отметок времени по умолчанию. Вы можете пометить свойство одного из этих типов с помощью @TeMPOraL, чтобы указать другую стратегию сохранения этого свойства.
- Если оба первых варианта у вас не работают, тогда (я уверен, вы знаете, что делать) - отключите это предупреждение
@SuppressWarnings("squid:S3437")
,
Я не совсем понимаю, что ваша БД принимает от 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 в Timestamp (принятый postgres) и обратно.