[Spring] DTO 내에 기본 생성자를 필수로 넣는 이유

stanley.·2024년 3월 5일

Spring

목록 보기
3/4
post-thumbnail

개요

DTO 코드를 만드는 경우 습관적으로 @Data 어노테이션을 명시하곤 했다.
문득, 직렬화, 역직렬화가 되는 것을 보며 객체와 데이터간의 바인딩이 어떻게 이루어지는지 이해하고 싶어졌다.

문제 - DTO 내 기본 생성자 (Default Constructor)의 부재 시

DTO내에 기본 생성자를 명시하지 않으면 아래와 같은 에러를 보게 된다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.yare.yareweb.domain.order.domain.dto.OrderApproveRequest (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

  • 에러 로그에서도 확인할 수 있듯이, 기본 생성자가 존재하지 않아 역직렬화가 불가능 하다는 것이다.
  • 그렇다면 기본 생성자가 의무적으로 필요한 이유는 무엇일까?

메시지 컨버터?

기본 생성자의 필요성을 알기에 앞서 메시지 컨버터라는 것이 무엇인지 알아야 한다.
아래 그림은 클라이언트가 요청을 전송했을 때, 요청 - 응답 간에 데이터가 변환되는 과정을 나타낸다.
아래 그림의 ArgumentResolver에 주목해야 한다.

어노테이션 기반 컨트롤러를 처리하는 RequestMappingHandlerAdaptor는 바로 이 ArgumentResolver를 호출해서 컨트롤러가 필요로 하는 다양한 파라미터의 값을 생성한다.
이 때, ArgumentResolver에서 JSON 형식의 데이터를 Object로 변환하기 위해 MessageConverter가 사용된다.
MessageConverter는 단어 뜻 그대로 전달된 HTTP 메시지를 변환하는 역할을 하는 것이다.

기본 생성자가 없는 경우의 MessageConverter

@Getter
public class OrderCreateRequest {

    private Long itemId;

    private String itemName;

    private int orderQuantity;

    private Long orderReqPrice;

    private Long orderFee;

    @Embedded
    private Address address;

    private String memberPhoneNo;

}
  1. BeanDeserializer 호출

  1. deserializeFromObject 호출

기본 생성자가 없는 경우에는 ctxt 즉, 컨텍스트 내부에 _nonStandardCreation은 true로 초기화되어 있기에 if문에 걸리게 된다.

  1. deserializeFromObjectUsingNonDefault()를 호출한다.

메서드명 그대로 default 즉, 기본 생성자가 없이 객체를 역직렬화하는 메서드를 호출한다.
뜬금없이 위 메서드를 호출하는가 싶지만, 코드 이미지가 잘려서 그렇지 (2)에 나타난 코드 라인 바로 다음에 명시된 메서드이다.

  • deseriallizeFromObjectUsingNonDefault() 메서드 내부를 보면, delegate가 없거나 property 기반의 생성자가 없는 경우 역직렬화가 불가능하다고 명시되어 있다.

  • 또한, deserializeFromObjectUsingNoDefault() 메서드의 가장 마지막 라인에 호출되는 handleMissingInstantiator() 메서드를 통해 !valueInst.canInstantiate() 조건에 걸려 서두에 언급했던 에러 메시지가 반환되고 있음을 알 수 있다.
  • 즉, 데이터를 다시 객체의 형태로 만드는 역직렬화 시 필요한 기본 생성자가 없어 DTO 객체를 생성하지 못하기 때문에 위와 같은 에러가 발생하게 되는 것이다.

해결책

  • 기본 생성자를 DTO 코드에 작성하자.
  • Property 기반의 클래스, 즉 @JsonProperty 어노테이션을 컬럼에 명시하자.

레퍼런스

https://blogshine.tistory.com/445

profile
🖥 Junior Developer.

0개의 댓글