안녕하세요 오늘은 Enum으로 Request, Response를 받는 방법을 이야기 하려고 합니다. Jpa 프로젝트를 진행 하다 보면 Enum 타입을 자주 사용하게 되는데요. 이경우 Enum으로 Request, Response를 받는 방법을 모르시는 경우가 많은 거 같습니다.
방법은 Jackson의 Deserializer, Serializer를 사용하면 간단하게 해결 가능합니다.
우선 기본적으로 제공하는 기능을 사용해서 Enum을 Request로 받아 보겠습니다.
1. TestController
<java />
@Slf4j
@RequestMapping("test")
@RestController
public class TestController {
@PostMapping("")
public ResponseEntity<ResponseDto> getTest(@RequestBody RequestDto requestDto){
log.info("requestDto : {}", requestDto);
ResponseDto responseDto = ResponseDto.builder()
.name("pooney responsedto")
.statusType(StatusType.DONE)
.build();
return ResponseEntity.ok(responseDto);
}
}
TestContoller에는 받은 requestDto를 로그로 출력하는 간단한 예제입니다.
2. StatusType.enum
<java />
@Getter
public enum StatusType {
DOING(0, "주문진행중"),
DONE(1, "주문완료");
private Integer code;
private String msg;
StatusType(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
위의 enum에서 지켜보셔야 하는 것은 code 값입니다. 0,1번인것을 기억해주세요

자 그러면 저는 Post Man 으로 요청해 보겠습니다.

위와 같이 StatusType을 0번으로 요청한 결과가 정상적으로 StatusType에 DOING이 찍히는걸 확인 할 수 있는데요 만약 StatusType의 코드값을 변경하면 어떻게 될까요? 저는 DOING( 0->3) , DONE(1->4) 번으로 code 값을 변경 해보겠습니다.
StatsType.enum
<java />
@Getter
public enum StatusType {
//code(0 -> 3번으로 변경)
DOING(3, "주문진행중"),
//code(1 -> 4번으로 변경)
DONE(4, "주문완료");
private Integer code;
private String msg;
StatusType(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
그러면 이번에는 변경된 StatusType의 code값 3번을 요청을 해보겠습니다.

아래과 같이 index range라는 장애가 발생합니다. 지금까지 code값을 매핑한것이 아니라 index를 기준으로 매핑을 했는데 3번이라는 범위를 벗아난 것을 요청하니 장애가 발생한 것입니다.
<java />
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.example.multiplex.type.StatusType` from number 3: index value outside legal index range [0..1]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.example.multiplex.type.StatusType` from number 3: index value outside legal index range [0..1]<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 3, column: 19] (through reference chain: com.example.multiplex.dto.RequestDto["statusType"])]
이러한 문제를 해결하는 방법이 @JsonCreator를 사용하는 것입니다.
<java />
@Getter
public enum StatusType {
DOING(3, "주문진행중"),
DONE(4, "주문완료");
private Integer code;
private String msg;
StatusType(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
@JsonCreator
public static StatusType of(Integer statusType) { //파라미터명을 일치 시켜야합니다.
return Arrays.stream(StatusType.values())
.filter(i -> i.code.equals(statusType))
.findAny()
.orElse(null);
}
}
@JsonCreator 사용하면서 주의할점은 반드시 StatusType of(Integer {statusType})의 파라미터명과 request의 필드명을 일치시켜야 정상 작동한다는 것입니다.


statusType을 3번으로 요청한 결과 의도한 매핑인 DOING이 출력된것을 확인 할 수 있습니다.
하지만 여기서 Respone를 확인 해보면 아래와 같이 statusType에 Enum의 name이 찍혀 있는것을 확인 할 수 있는데요

그러면 저것을 msg인 "주문완료, 주문진행중"으로 표시할 수 있는 방법이 없을까요? 그것은 바로 @JsonValue 입니다.
3.
4. StatusType.enum
<java />
@Getter
public enum StatusType {
DOING(3, "주문진행중"),
DONE(4, "주문완료");
private Integer code;
//해당 값으로 response가 내려갑니다
@JsonValue
private String msg;
StatusType(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
@JsonCreator
public static StatusType of(Integer statusType) {
return Arrays.stream(StatusType.values())
.filter(i -> i.code.equals(statusType))
.findAny()
.orElse(null);
}
}
Response로 내려보내길 원하는 필드에 @JsonValue를 붙여주시면 간단하게 해결 할 수 있습니다. 여기서 주의 해야할점은 저는 @Getter를 사용하기 때문에 해당필드에 붙여주었지만 아닐 경우에는 getter인 getMsg()에 붙여주시면 됩니다.
이제 결과를 확인해보겠습니다.

정상적으로 msg인 "주문완료" 가 출력되는 것을 확인 할 수 있습니다. 물론 @JsonCreator를 사용하지 않고 formatter를 사용하는 방법도 있지만 저는 간단하게 사용가능한 것을 사용해서 해결을 해보았습니다. 많은 분들에게 도움이 되었으면 좋겠습니다.

'Spring boot' 카테고리의 다른 글
[Spring-Boot] SecureRandom 난수 생성시 Freeze 문제 (0) | 2024.07.18 |
---|---|
[Spring-boot] Mattermost Bot 사용 (0) | 2024.04.24 |
Spring boot - Transaction Propagation (1) | 2022.07.15 |
spring boot - 트랜잭션 (0) | 2022.07.01 |
Spring boot - Docker를 이용한 JENKINS 설치 (0) | 2022.06.28 |