Skip to content

Cannot construct instance of xxxx (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) 이슈 #150

@daadaadaah

Description

@daadaadaah

What

  • com.fasterxml.jackson.databind.exc.InvalidDefinitionException는 Jackson 데이터 바인딩 라이브러리에서 발생하는 예외 중 하나로, 정의가 잘못되었거나 유효하지 않은 데이터를 역직렬화할 때 발생한다.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.hcommerce.heecommerce.order.dto.OrderForm` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
2023-07-18T02:38:50.124+09:00  WARN 53555 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.hcommerce.heecommerce.order.dto.OrderForm]]

Why

  • 스프링은 기본적으로 직렬화/역직렬화에 Jackson 라이브러리를 기본으로 사용하고 있는데, 그 Jackson 라이브러리는 직렬화/역직렬화 할 때, 기본생성자가 없으면 동작하지 않는다.
  • 그런데, 나는 다음과 같이 생성자가 있는데, 기본생성자가 없기 때문에 발생한 문제 였다.
@Getter
public class OrderForm {

    //.. 생략
    
    @Builder
    public OrderForm(
        UUID orderUuid,
        int userId,
        RecipientInfoForm recipientInfoForm,
        OutOfStockHandlingOption outOfStockHandlingOption,
        UUID dealProductUuid,
        int orderQuantity,
        PaymentMethod paymentMethod
    ) {
        this.userId = userId;
        this.orderUuid = orderUuid;
        this.recipientInfoForm = recipientInfoForm;
        this.outOfStockHandlingOption = outOfStockHandlingOption;
        this.dealProductUuid = dealProductUuid;
        this.orderQuantity = orderQuantity;
        this.paymentMethod = paymentMethod;
    }
}
  • 기본생성자가 없기 때문에 나타난 문제였다.
  • 왜 기본 생성자가 필요한 걸까?

How

  • JSON 데이터를 역직렬화하려면 매개변수가 없는 기본 생성자가 있거나,
  • Jackson 어노테이션을 사용하여 역직렬화할 생성자를 명시적으로 지정해야 합니다.
  • @ConstructorProperties 추가

@ConstructorProperties
생성자의 파라미터에 해당하는 getter 이름을 지정해주기 위한 자바 빈 애노테이션
Jackson이 JSON 형태의 데이터를 deserialize 할 때 기본 생성자를 사용해 인스턴스를 생성하고 setter로 필드 값을 셋팅한다.
그런데, immutable 객체의 경우 setter가 존재하지 않기 때문에 @ConstructorProperties로 호출할 생성자와 파라미터에 해당하는 getter 이름을 직접 지정

Before

@Getter
public class OrderForm {

    //.. 생략
    
    @Builder
    public OrderForm(
        UUID orderUuid,
        int userId,
        RecipientInfoForm recipientInfoForm,
        OutOfStockHandlingOption outOfStockHandlingOption,
        UUID dealProductUuid,
        int orderQuantity,
        PaymentMethod paymentMethod
    ) {
        this.userId = userId;
        this.orderUuid = orderUuid;
        this.recipientInfoForm = recipientInfoForm;
        this.outOfStockHandlingOption = outOfStockHandlingOption;
        this.dealProductUuid = dealProductUuid;
        this.orderQuantity = orderQuantity;
        this.paymentMethod = paymentMethod;
    }
}

After

@Getter
public class OrderForm {

     //.. 생략
    
    @Builder
    @ConstructorProperties({ // ✨ 추가
        "orderUuid",
        "userId",
        "recipientInfoForm",
        "outOfStockHandlingOption",
        "dealProductUuid",
        "orderQuantity",
        "paymentType"
    })
    public OrderForm(
       //.. 생략
    ) {
       //.. 생략
    }
}

Reference

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions