본문 바로가기

STUDY/Spring

JPA | @Converter, @Convert (+ @Convert 먹히지 않을 때)

지금 하는 프로젝트가 레거시 디비를 이용해야 하는데.. 데이터 베이스 구조나 값을 변경할 수는 없고..
1, 2 등에 해당하는 값을 일일이 찾아보는 것도 귀찮아서 ENUM으로 변환해서 사용하고자 한다..

ENUM 정의

예를 들어 1은 진돗개, 2는 삽살개...를 의미한다고 할 때..
대충 이런 구조의 ENUM을 정의할 수 있다.

@Getter
public enum DogBreed {
    JINDO(1, "진돗개"),
    SAPSAL(2, "삽살개");

    private int num;
    private String name;

    Animal(int num, String name) {
        this.num = num;
        this.name = name;
    }
}

한 두개 일 때는 외울만 하지만 값도 여러개에 테이블마다 1, 2, 3... 이렇게 계속 있으면 짜증나니까..
이럴 때 @Converter@Convert를 사용하면 짱짱굿

ENUM에서 디비 값으로 상수를 찾는 함수를 작성

디비에는 숫자로 저장되어 있기 떄문에 해당 숫자로 상수를 찾는 함수를 만든다.
여기까지만 하면 거의 끝

public static DogBreed ofNum(Integer ogNum) {
    return Arrays.stream(DogBreed.values())
            .filter(val -> val.getNum() === ogNum)
            .findAny()
            .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 동물이네요.."));
}

@Converter 작성

클래스 선언부에 @Converter애너테이션을 등록한 뒤 AttributeConverter를 구현하면 된다.
두 개의 메서드를 오버라이딩 하면 끝!
convertToDatabaseColumn()메서드는 이름만 봐도 알 수 있듯 어떤 값을 디비에 저장할지 알려주는 거다..
디비에 1, 2, 3.. 이런 숫자를 저장해야 하므로 getNum()을 해준다.

Wrapper Class로만 작성할 수 있다.

@Converter
public class BreedConverter implements AttributeConverter<DogBreed, Integer> {

    @Override
    public Integer convertToDatabaseColumn(DogBreed attribute) {
        return attribute.getNum();
    }

    @Override
    public DogBreed convertToEntityAttribute(Integer dbData) {
        return DogBreed.ofNum(dbData);
    }

}

Entity에서 @Convert애너테이션으로 등록

@Convert애너테이션으로 작성한 컨버터 클래스를 등록하면 끝이다..

@Entity
public class AnimalHistory {

    @Convert(converter = BreedConverter.class)
    private DogBreed breed; 
}

@Id컬럼에서 사용할 때

@Id@Convert를 함께 사용하면 안먹힌다. 그냥 몇 번째 값인지만 등록됨..
부득이하게 함께 사용해야 할 경우에는 @IdClass()를 사용할 수 있다.

@Column()도 IdClass에 정의해야 함!

@IdClass(AnimalHistoryId.class)
@Entity
public class AnimalHistory {

    @Id
    private DogBreed breed; 
}

@AllArgsConstructor
@NoArgsConstructor
public class AnimalHistoryId implements Serializable {

    @Column(name = "DOG_BREED", nullable = false)
       @Convert(converter = BreedConverter.class)
    private DogBreed breed;

    // equals and hashcode 오버라이딩 필수
}