Search

HTTP body에 enum 넣기

태그
Java
Spring
분류
트러블슈팅
생성 일시
2023/08/17 04:41
프로젝트
42PAW

역직렬화 실패?

컨트롤러 작업을 하던 중, 포스트맨으로 요청을 보내면 500 Internal Server Error가 발생하면서 위와 같은 에러 메세지가 뜨게 되었다. 에러 메세지를 읽어보니 Object Value를 역직렬화 하는데 실패했다는데, 에러를 읽자마자 메세지에서 DTO로 담는 과정에서 변환이 안되는건가라는 생각이 들었다.
이 문제는 에러 메세지에도 자세히 써져있지만 HTTP 메세지에 담겨있는 문자열 데이터를 DTO에 담기위해 역직렬화하는 과정에서, 기본 생성자를 호출하려는데 알맞는 생성자가 없어서 발생하는 에러였다.
에러 메세지에 자세히 나와있기도하고 해당 DTO에는 launguage라는 열거형 타입 딱 한 개만 들어있던터라 바로 문제를 알아챘지만, 만약 필드가 많았다면 오류를 찾기 어려울 것 같아서 트러블슈팅을 남기게 되었다.

Jackson2HttpMessageConverter

사실 위 문제는 기본 생성자만 하나만 추가해주면 해결되는 문제이다. 그렇다면 왜 기본 생성자가 있어야만 하는지에 대해 알아보자.
스프링은 HTTP 메세지의 body를 읽기 위해 HttpMessageConverter를 사용한다. 클라이언트로부터 값을 받으면 여러 Converter 중에서 해당 값을 읽을 수 있는 Converter를 찾는다. 읽을 수 있는 컨버터를 찾으면 read() 메서드를 통해 값을 읽고 원하는 Object로 변환한다.
스프링에서 JSON형 변환을 담당하는 것은 Jackson2HttpMessageConverter인데, @RequestBody 로 JSON 데이터가 넘어오면 Jackson2HttpMessageConverter의 ObjectMaper를 사용해서 Object로 변환한다.
ObjectMapper에서는 BeanDeserializer의 deserialize()에서 기본 생성자를 호출해 Object를 생성한다. 그 다음 JSON에서 value를 가져와 리플렉션으로 값을 저장한다.
이러한 과정에서 기본 생성자가 필요하기 때문에 기본 생성자가 없다면 에러가 발생하는 것이다. 해결 방법은 기본 생성자를 직접 만들어주거나 클래스에 @NoArgsConstructor를 추가해주면 된다. 만약 필드에 final이 선언되어 있다면, final을 해제해주어야 기본 생성자로 값을 저장할 수 있다.

참고