programing

Spring Boot 2로 업그레이드한 후 Object Mapper가 기본 컨스트럭터 없이 역직렬화할 수 없음

iphone6s 2023. 4. 2. 10:07
반응형

Spring Boot 2로 업그레이드한 후 Object Mapper가 기본 컨스트럭터 없이 역직렬화할 수 없음

DTO는 다음과 같습니다.

@Value
public class PracticeResults {
    @NotNull
    Map<Long, Boolean> wordAnswers;
}

@Value
public class ProfileMetaDto {

    @NotEmpty
    String name;
    @Email
    String email;
    @Size(min = 5)
    String password;
}

@Value는 생성자를 생성하는 롬복 주석입니다.즉, 이 클래스에는 no-arg 생성자가 없습니다.

Spring Boot 1.4.3을 사용했습니다.릴리즈 및ObjectMapperbean은 이러한 오브젝트를 JSON에서 역직렬화할 수 있었습니다.

Spring Boot 2.0.0으로의 업그레이드 후.M7 다음과 같은 예외를 받습니다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of PracticeResults (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Spring Boot 1.4.3에서 사용되는 Jackson 버전은2.8.10및 Spring Boot 2.0.0 용입니다.M7은2.9.2.

이 문제를 구글로 검색하려고 했지만 해결 방법만 찾았습니다.@JsonCreator또는@JsonProperty.

그러면 Spring Boot 1.4.3에서는 동작하고 Spring Boot 2에서는 동작하지 않는 이유는 무엇일까요?이전 버전과 동일하게 동작하도록 bean을 설정할 수 있습니까?

Lombok 버전 1.16.20의 변경을 어기고 있기 때문에 다음 속성을 설정할 필요가 있습니다.lombok.config파일(이 파일이 없는 경우 프로젝트 루트에 파일을 만들 수 있습니다):

lombok.anyConstructor.addConstructorProperties=true

이는 Lombok changelog(https://projectlombok.org/changelog)에 설명되어 있습니다.

그 후 잭슨은 @Value를 다시 인정해야 합니다.

GitHub 관련 이슈에 관심이 있으실 수도 있습니다.단, GitHub 관련 이슈에 대한 것입니다.@Data: https://github.com/rzwitserloot/lombok/issues/1563

이 문제를 해결할 수 있는 한 가지 방법이 있습니다.잭슨 파라미터 이름 모듈을 사용합니다.이것은 기본적으로 스프링부트 2에 포함되어 있습니다.이 후에 잭슨은 오브젝트를 역직렬화 할 수 있다.그러나 이 기능은 개체에 둘 이상의 속성이 있는 경우에만 작동합니다.단일 속성인 경우 다음 오류 메시지가 표시됩니다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `SomeClassName` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

다음과 같은 이유:

연관된 클래스의 새 인스턴스를 인스턴스화하는 데 사용할 생성자 및 공장 메서드를 정의하는 데 사용할 수 있는 마커 주석입니다.

참고: 작성자 메서드(컨스트럭터, 공장 메서드)에 주석을 달 때 방법은 다음 중 하나여야 합니다.

  • 단일 인수 생성자/공장 방법 없음JsonProperty인수에 대한 주석: 그렇다면 이것은 소위 "위임 크리에이터"입니다.이 경우 잭슨은 먼저 JSON을 인수의 유형에 바인드한 다음 크리에이터를 호출합니다.이것은 종종 와 함께 사용됩니다.JsonValue(시리얼라이제이션에 사용).
  • 모든 인수에 다음 중 하나를 주석으로 붙이는 생성자/공장 메서드JsonProperty ★★★★★★★★★★★★★★★★★」JacksonInject

, 모든 「 」, 「 」가 것에 .JsonProperty주석은 파라미터 이름을 검출할 수 있는 확장 모듈 중 하나를 사용하지 않는 한 실제 이름을 지정해야 합니다.이는 8 이전 버전의 JDK에서는 바이트 코드에서 파라미터 이름을 저장하거나 가져올 수 없기 때문입니다.그러나 JDK 8(또는 Paranamer와 같은 도우미 라이브러리 또는 Scala나 Kotlin과 같은 다른 JVM 언어를 사용)에서는 이름을 지정하는 것은 옵션입니다.

Lombok을 사용하여 이 문제를 처리하기 위해 다음 해결 방법을 사용했습니다.

@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}

클래스 내에 최종 필드가 몇 개 있고 특정 컨스트럭터를 사용하여 POJO를 역직렬화하는 Object creator를 원하는 경우@Data합니다.@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)필요한 생성자 매개변수를 구체화한다.@JsonProperty("<field_name>")예를 다음에 나타냅니다.

package test.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.Date;

@Data
public class KafkaEventPojo {
    private final String executionId;
    private final String folder;
    private final Date created_at;

    private Date updated_at;
    // ... other params
    
    /**
     * Instantiates a new Kafka event pojo.
     *
     * @param executionId the execution or flow id of the event lifecycle
     * @param folder      the folder to be retrieved
     */
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public KafkaEventPojo(@JsonProperty("executionId") String executionId, @JsonProperty("folder") String folder) {
        this(executionId, folder, new Date(System.currentTimeMillis()));
    }

    private KafkaEventPojo(String executionId, String folder, Date date) {
        this.executionId = executionId;
        this.folder = folder;

        this.created_at = date;
        this.updated_at = date;
    }
    
    // ... other logic
}

이 문제와 필드 없는 디폴트 컨스트럭터를 만들면 문제가 사라지게 되는 해결책이 있었습니다.

했지만, 은 이 하는 것을 하지 않았다: this에 、 만에 、 루 i 、 루 i 、 i i i i i i 。(mode = JsonCreator.Mode.PROPERTIES)

제 고민을 정말 해결한 건@JsonProperty이치노

최종 결과는 다음과 같습니다.

@Value
public class ServerTimeResponse {

    long serverTime;

    @JsonCreator
    public ServerTimeResponse(@JsonProperty("serverTime") long serverTime) {
        this.serverTime = serverTime;
    }

}

다른 '더 넣어야 ', '더 많이 넣어야 한다', '더 많이 넣어야 한다', '더 많이 넣어야 한다' 이런 에요.@Value에게 롬복의 을 @JsonCreator 상에서

@AllArgsConstructor(onConstructor_={@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)})

JDK8+ 를 사용하고 있는 경우는, 여기의 다른 회답과는 약간 다른 구문을 참조해 주세요( 구문은 javadoc 에 기재되어 있습니다).

freefair gradle에 을 추가하도록 .build.gradle:

lombok {
    config['lombok.anyConstructor.addConstructorProperties'] = 'true'
}

중 이한 경우 에서 "Native Mode"를 입니다.@RegisterForReflection합니다.

링크에 대한 정보 검색

롬복 버전을 org.projectlombok:lombok:1.18.0'으로 업그레이드하여 사용할 수 있게 되었습니다.

언급URL : https://stackoverflow.com/questions/48330613/objectmapper-cant-deserialize-without-default-constructor-after-upgrade-to-spri

반응형