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) 가 발생하게 됩니다.
실무에서 자주 발생하는 문제
- API 응답에서
"status": "READY"
가 아닌"준비중"
이나"R"
처럼 변환된 값을 보내고 싶을 때 - 클라이언트가
"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 직렬화 문제로 더 이상 삽질하지 마세요!
'IT > Java' 카테고리의 다른 글
[Java] Record vs. Lombok – 무엇을 언제 써야 할까? (0) | 2025.05.31 |
---|---|
[Java] Enum을 똑똑하게 사용하는 실무 패턴 정리 (1) | 2025.05.25 |
[Java] Optional이란?? (0) | 2025.05.23 |
[Java] List Grouping 하는 방법 (0) | 2025.02.10 |
Error와 Exception (0) | 2021.04.08 |
댓글