[JPA] JPA 2.1 이하에서 LocalDate/LocalDateTime 사용하기

by 스뎅(thDeng) on

JPA 2.1은 Java 8 이전에 나왔기 때문에, Java 8에서 추가된 LocalDateLocalDateTime은 기본으로 지원하지 않는다. LocalDateTimeTimestamp 타입에 넣으려고 하면 에러를 뱉는다. 에러로그를 봐서는 바이너리로 저장을 시도하는듯 싶다. (JPA 2.2부터는 LocalDate, LocalDateTime, LocalTime, OffsetTime, OffsetDateTime 등을 기본 타입으로 지원한다.)

2018-11-23 16:48:51.900 ERROR 15371 --- [nio-8081-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : Data truncation: Incorrect date value: '\xAC\xED\x00\x05sr\x00\x0Djava.time.Ser\x95]\x84\xBA\x1B"H\xB2\x0C\x00\x00xpw\x07\x03\x00\x00\x07\xE2\x0B\x17x' for column 'joinDate' at row 1

joinDate 컬럼은 date 타입인데 너 왜 바이너리 넣었어?? 잘못된 데이터야. 라고 한다.

간단히 쓸 수 있는 방법으로 converter를 만들어주면 된다.

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Optional;

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime localDateTime) {
        return Optional.ofNullable(localDateTime)
                .map(Timestamp::valueOf)
                .orElse(null);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
        return Optional.ofNullable(timestamp)
                .map(Timestamp::toLocalDateTime)
                .orElse(null);
    }

}
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;
import java.util.Optional;

@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return Optional.ofNullable(localDate)
                .map(Date::valueOf)
                .orElse(null);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return Optional.ofNullable(date)
                .map(Date::toLocalDate)
                .orElse(null);
    }

}

엔티티 필드에 @Convert로 원하는 converter를 지정해 주면 끝!!

@Entity
@Table(name = "user")
public class BuyUser {

    @Id
    private String id;

    @NotNull
    private String name;

    @Convert(converter = LocalDateConverter.class)
    private LocalDate joinDate;

}

Hibernate를 쓰는 경우 hibernate-java8 등을 쓰면 변환을 지원해 주기도 한다. (현재는 deprecated되었고, hibernate-core를 사용하라고 쓰여 있다.) Hibernate 5.3 부터는 JPA 2.2를 지원한다.

참고

별도로 명시하지 않을 경우, 이 블로그의 포스트는 다음 라이선스에 따라 사용할 수 있습니다: Creative Commons License CC Attribution-NonCommercial-ShareAlike 4.0 International License