안녕하세요 오늘은 Enum으로 Request, Response를 받는 방법을 이야기 하려고 합니다. Jpa 프로젝트를 진행 하다 보면 Enum 타입을 자주 사용하게 되는데요. 이경우 Enum으로 Request, Response를 받는 방법을 모르시는 경우가 많은 거 같습니다.
방법은 Jackson의 Deserializer, Serializer를 사용하면 간단하게 해결 가능합니다.
우선 기본적으로 제공하는 기능을 사용해서 Enum을 Request로 받아 보겠습니다.
TestController
@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를 로그로 출력하는 간단한 예제입니다.
StatusType.enum
@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
@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번이라는 범위를 벗아난 것을 요청하니 장애가 발생한 것입니다.
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를 사용하는 것입니다.
@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 입니다.
StatusType.enum
@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 |