본문 바로가기
IT/Java

[Java] Enum을 JSON으로 직렬화할 때 주의할 점 – @JsonValue, @JsonCreator 활용법

by eddie_factory 2025. 6. 1.
반응형

Spring Boot 기반 REST API에서 enum을 사용하는 경우,
프론트와 JSON 데이터를 주고받을 때 직렬화(서버 → JSON), 역직렬화(JSON → 서버) 문제가 자주 발생합니다.

  • API 응답 시 Enum.name()이 그대로 나가거나
  • 클라이언트에서 String 값을 보냈는데 Jackson이 Enum으로 못 바꾸는 경우
    이런 상황은 프론트와 API의 통신 오류로 이어질 수 있습니다.

이번 글에서는 실무에서 자주 발생하는 Enum 매핑 이슈
이를 해결할 수 있는 @JsonValue / @JsonCreator 사용법을 정리해보겠습니다.

기본 Enum 직렬화 방식은?

다음과 같은 Enum이 있다고 가정합니다.

public enum Status {
    READY, RUNNING, DONE
}

기본적으로 Spring Boot에서 이 Enum을 API 응답으로 내보내면 다음처럼 직렬화됩니다.

"status": "READY"

즉, Enum.name() 값이 그대로 JSON으로 나갑니다.

문제는 프론트에서 "ready" 또는 "R" 같은 값으로 보냈을 경우,
역직렬화 중에 매핑 실패 (HttpMessageNotReadableException) 가 발생하게 됩니다.

실무에서 자주 발생하는 문제

  1. API 응답에서 "status": "READY"가 아닌 "준비중"이나 "R"처럼 변환된 값을 보내고 싶을 때
  2. 클라이언트가 "R" 같은 코드 값으로 Enum 요청을 보냈을 때
    → 서버가 매핑하지 못하고 400 에러 발생

이런 문제는 모두 Enum ↔ JSON 간의 표현 방식 차이 때문입니다.

 

해결법 1 – @JsonValue로 직렬화 제어

Enum을 JSON으로 변환할 때 어떤 값을 사용할지 지정할 수 있습니다.

public enum Status {
    READY("R"), RUNNING("G"), DONE("D");

    private final String code;

    Status(String code) {
        this.code = code;
    }

    @JsonValue
    public String getCode() {
        return code;
    }
}

결과:

"status": "R"
  • 클라이언트가 보기 좋은 값으로 응답할 수 있습니다.
  • 단, 역직렬화(받을 때)는 여전히 실패합니다.

 

해결법 2 – @JsonCreator로 역직렬화 제어

클라이언트가 보낸 "R" 값을 서버에서 Enum으로 매핑하려면,
생성자 또는 static 메서드에 @JsonCreator를 붙여야 합니다.

public enum Status {
    READY("R"), RUNNING("G"), DONE("D");

    private final String code;

    Status(String code) {
        this.code = code;
    }

    @JsonValue
    public String getCode() {
        return code;
    }

    @JsonCreator
    public static Status fromCode(String code) {
        return Arrays.stream(Status.values())
            .filter(s -> s.getCode().equals(code))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("Unknown code: " + code));
    }
}

이렇게 하면:

  • 응답: "status": "R"
  • 요청: { "status": "R" }Status.READY 로 잘 매핑됨

 

주의할 점

  • @JsonValue@JsonCreator는 반드시 쌍으로 사용하는 것이 좋습니다.
    하나만 설정하면 응답/요청 중 한쪽에서만 적용됩니다.
  • @JsonCreator는 생성자 대신 static factory method에서 사용하는 것이 더 안전하고 명확합니다.
  • 필드 타입이 Enum일 경우 Jackson은 내부적으로 Enum.name()을 기본으로 사용합니다.

 

추가 팁 – 컨버터 방식 (JPA + DB용)

JPA에서 Enum ↔ DB 매핑 시에도 동일한 이슈가 발생할 수 있습니다.
DB에는 "R"이 저장되는데, JPA는 READY로만 인식하는 경우입니다.

@Converter(autoApply = true)
public class StatusConverter implements AttributeConverter<Status, String> {
    @Override
    public String convertToDatabaseColumn(Status status) {
        return status.getCode();
    }

    @Override
    public Status convertToEntityAttribute(String dbCode) {
        return Status.fromCode(dbCode);
    }
}
  • 이렇게 하면 JSON뿐 아니라 DB와도 코드 값으로 매핑이 가능합니다.

 

마무리

Spring Boot + Jackson 환경에서 enum을 사용하는 경우,
기본 직렬화 방식만 쓰면 클라이언트와의 JSON 데이터 매핑 문제가 자주 발생합니다.

이런 문제는 @JsonValue, @JsonCreator를 적절히 활용하면 쉽게 해결할 수 있으며,
DB까지 통합하려면 JPA 컨버터까지 함께 고려하는 것이 좋습니다.

목적 사용 애너테이션
JSON 응답 값 커스터마이징 @JsonValue
JSON 요청 값 매핑 처리 @JsonCreator
DB ↔ Enum 매핑 AttributeConverter

이제는 enum 직렬화 문제로 더 이상 삽질하지 마세요!

반응형

댓글