Programming-[Backend]/Java

[작성중] Enum 사용: @Converter 적용하기

컴퓨터 탐험가 찰리 2025. 6. 23. 09:25
728x90
반응형

 

배경

Enum을 사용하면 규격화된 스펙으로 특정 속성값들을 편리하게 처리할 수 있다. 클래스처럼 사용할 수도 있어서 내부에 관련된 값과 메서드들을 선언하여 캡슐화하여 코드를 관리할 수도 있다.

 

public enum UploadStatus {
    PROCESSING,
    DONE,
    FAIL

    public static UploadStatus from(...) {
        return ...
    }
}

 

만약 mysql을 사용한다면 DB에서 enum 타입 자체를 지원하지는 않기 때문에 다음과 같이 Entity에 해당 타입을 선언하면서 @Enumerated를 선언해준다. 그러면 내부적으로는 Enum을 통해 규격화되고, 통일성 있는 타입으로 사용할 수 있으면서도 DB에는 String으로 처리되어 들어가게 된다.

@Enumerated(EnumType.STRING)
@Column(length = 20, nullable = false)
private UploadStatus status;

 

 

Enum의 중요한 특성 중 하나는 선언된 값 외에 다른 값이 입력되면 에러가 난다는 것이다. 만약 Enum(PROCESSING, DONE, FAIL) 이

라는 타입이 있다면 CANCEL이라는 잘못된 타입으로 들어온다면 바로 에러가난다. 즉, 예를들어 위에서 정의한 status 값을 목록 API에 내려주는데, 조회한 데이터 중 하나라도 잘못된 타입이 들어간다면 서비스 자체가 장애가 난다. Enum이 아니라 일반 String으로 했다면 잘못된 값이더라도 일단 조회는 되고, 값에 의한 에러가 나기 때문에 개발자가 수정하면 되는데 Enum을 너무 규격화하면 서비스 전체가 장애가 나버릴 수도 있다.

 

단일 서버이고, API만 사용하여 정확히 처리되기만 한다면 문제가 발생할 확률이 적지만 쿼리를 통해 DB를 손보는 일이 있다던가, 실수로 데이터를 DB만을 통해 잘못 집어넣는 경우가 발생할 수 있다. 물론 절대 이렇게 하면 안되지만, 운영상의 이유로 이런 일이 있을 때가 절대로 없다는 보장을 할수가 없다. 이런 이유로 Enum에 UNKNOWN과 같은 기본 타입을 선언해두고, @Converter를 사용하는 방식이 있다.

 

 

적용 방법

Enum마다 만들어줘야해서 약간 번거로울 수는 있으나, Enum의 장점을 누리면서 위에서 언급한 문제들을 해결하고 싶다면 아래 코드들을 통해 Enum마다 선언 처리해줘야한다. BaseEnum과 SafeEnumConverter는 공통 코드이다.

 

public interface BaseEnum {
    String name();
    static <E extends Enum<E>> E safeValueOf(Class<E> enumClass, String value, E defaultValue) {
        try {
            return Enum.valueOf(enumClass, value);
        } catch (Exception e) {
            return defaultValue;
        }
    }
}

 

@Converter
public abstract class SafeEnumConverter<E extends Enum<E>> implements AttributeConverter<E, String> {

    private final Class<E> enumClass;
    private final E defaultValue;

    protected SafeEnumConverter(Class<E> enumClass, E defaultValue) {
        this.enumClass = enumClass;
        this.defaultValue = defaultValue;
    }

    @Override
    public String convertToDatabaseColumn(E attribute) {
        return attribute == null ? null : attribute.name();
    }

    @Override
    public E convertToEntityAttribute(String dbData) {
        if (dbData == null) return defaultValue;

        try {
            return Enum.valueOf(enumClass, dbData);
        } catch (IllegalArgumentException e) {
            return defaultValue;
        }
    }
}

 

 

 

프로그램에서 사용하는 Enum과 DB에서 받아온 Entity값 간의 변환이 일어날 때, 값이 없거나 잘못된 값일 때 처리해주는 코드이다. convertToEntityAttribute 메서드에서는 Enum에 잘못된 value가 들어오거나 null이 들어오면 기본값으로 반환해준다.

 

그리고 Enum마다 아래 메서드를 만들어주면 된다. 위 예시에서 선언한 UploadStatus Enum에 UNKNOWN 타입을 선언해주어야 한다.

@Converter(autoApply = true)
public class UploadStatusConverter extends SafeEnumConverter<UploadStatus> {
    public UploadStatusConverter() {
        super(UploadStatus.class, UploadStatus.UNKNOWN);
    }
}

 

 

@Converter

728x90
반응형