@JsonCreator with Spring web controller (enum)
이번엔 request dto에 enum타입을 받아올 때, Jackson에서 제공하는 기본 EnumDeserializer 외에 내가 지정한 setter를 사용하는 방법에 대해 기록해보려 합니다.
(게시글에서 만큼은 네이밍의 고통을 받고싶지않아 조금 날림입니다.)
간단한 테스트 코드를 구성해봅니다.
@RestController
public class TestController {
@PostMapping("/hello")
public String matchEnumTest(@RequestBody RequestDto requestDto){
return "hello world";
}
}
@Getter
public class RequestDto {
private TestEnum testEnum;
}
public enum TestEnum {
TEST1,
TEST2
}
컨트롤러에서는 RequestDto라는 친구를 받아오게되고, 이때 testEnum이라는 필드를 가지고있습니다.
기본적으로 json body를 받을때, json to object 과정에서 deserialize 는Jackson라이브러리에서 실행됩니다.
이 경우 enum value의 name과 완전 동일한경우, 기본 deserialize가 있기에 문제는 없으나, 변수가 조금이라도 틀리게되면 바로 이런 에러를 맞이하게됩니다.
JSON parse error: Cannot deserialize value of type `enum package`
이경우 해당 에러를 맞이하지않고, 내가 지정한 setter를 사용하게끔 지원하는 @JsonCreator라는 어노테이션이 필요합니다.
코드를 조금 바꿔보겠습니다.
public enum TestEnum {
TEST1,
TEST2
@JsonCreator
public static TestEnum fromTestEnum(String val){
for(TestEnum testEnum : TestEnum.values()){
if(testEnum.name().equals(val)){
return testEnum;
}
}
return null;
}
}
다음과 같이 지정하는경우, API 요청을 받아올때, testEnum 값으로 받은 string은 @JsonCreator를 지정한 메서드의 파라미터로 들어가게 되고, 해당 메서드 기능을 통해, request dto에 저장되게됩니다.
이게 대체 왜그럴까? 라는 궁금증이 있어서 디버그모드로 조금 찾아본결과 BasicDeserializerFactory 메서드 실행과정에 다음과같은 로직을 찾을 수 있었습니다.
AnnotatedMethod factory : beanDesc.getFactoryMethods()
해당 과정에서 내가 세팅한 setter를 받아오고
deser이라는 변수에 deserializer 관련 메서드를 저장하게 되면서 이용되게 되는 구조였습니다.