source

Lombok 1.18.0과 Jackson 2.9.6이 함께 작동하지 않음

gigabyte 2023. 3. 20. 23:17
반응형

Lombok 1.18.0과 Jackson 2.9.6이 함께 작동하지 않음

업데이트 후 역직렬화가 실패합니다.

다음에서 마이크로 서비스를 업데이트했습니다.Spring 1.5.10.RELEASE로.Spring 2.0.3.RELEASE또,lombok부터1.16.14로.1.18.0그리고.jackson-datatype-jsr310부터2.9.4로.2.9.6.

JSON 문자열 -

{"heading":"Validation failed","detail":"field must not be null"}

클래스 -

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

   private final String heading;
   private final String detail;
   private String type;
}

메서드 호출 -

ErrorDetail errorDetail = asObject(jsonString, ErrorDetail.class);

역직렬화에 사용되는 방법 -

import com.fasterxml.jackson.databind.ObjectMapper;
// more imports and class defination.

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

오류 -

java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.foo.bar.ErrorDetail` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"heading":"Validation failed","detail":"field must not be null"}"; line: 1, column: 2]

Lombok이 생성을 중지했습니다.@ConstructorProperties버전 1.16.20(changelog 참조)의 컨스트럭터에서는 모듈을 사용하는 Java 9+ 어플리케이션이 파손될 수 있습니다.이 주석에는 생성자의 매개 변수 이름이 포함됩니다(클래스를 컴파일할 때 제거되므로 실행 시 매개 변수 이름을 계속 검색할 수 있도록 해결 방법).기본적으로 주석은 생성되지 않으므로 Jackson은 필드 이름을 생성자 매개 변수에 매핑할 수 없습니다.

해결책 1: 사용@NoArgsConstructor그리고.@Setter하지만 당신은 불변성을 잃게 될 것이다(그것이 당신에게 중요하다면).

업데이트: Just(그냥)@NoArgsConstructor그리고.@Getter(없음)@Setter(이유)도 동작할 수 있습니다.이렇게 하면 적어도 일반(비반사) 코드로부터 클래스를 불변 상태로 유지할 수 있습니다.

해결책 2: 행이 포함된 파일을 사용하여 주석을 다시 생성하도록 롬복 구성lombok.anyConstructor.addConstructorProperties = true. (모듈을 사용하는 경우,java.desktop모듈 경로 상에 있습니다.)를 추가한 후 정리하고 다시 컴파일합니다.lombok.config파일.

해결책 3: Jackson의 Builder 지원을 lombok의 Builder 지원(@Jacksonized)@Builder/@SuperBuilder@Randakar에서 설명한 바와 같이 이 질문에 대한 답변입니다.

솔루션 4: 컴파일 시javac(Java 8 이상), 추가-parameters명령어로 이동합니다.이렇게 하면 생성된 클래스 파일에 생성자 및 메서드의 매개 변수 이름이 저장되므로 리플렉션을 통해 검색할 수 있습니다.

편집: 이 답변은 좀 오래되었습니다.새로운 것이 있다@Jacksonized이 답변의 보일러 플레이트의 대부분을 관리하는 https://projectlombok.org/features/experimental/Jacksonized,에서 주석을 작성합니다.


잭슨과 롬복의 플레이를 잘 할 수 있는 가장 좋은 방법은 항상 DTO를 불변하게 만들고, 잭슨에게 빌더를 사용하여 오브젝트로 역직렬화하라고 말하는 것입니다.

불변 객체는 컴파일러가 현장에서 필드를 수정할 수 없는 경우 훨씬 더 적극적인 최적화를 수행할 수 있다는 단순한 이유로 좋은 아이디어입니다.

이를 위해서는 JsonDeserialize와 JsonPojoBuilder의 두 가지 주석이 필요합니다.

예:

@Builder
@Value // instead of @Data
@RequiredArgsConstructor
@NonNull // Best practice, see below.
@JsonDeserialize(builder = ErrorDetail.ErrorDetailBuilder.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

   private final String heading;

   // Set defaults if fields can be missing, like this:
   @Builder.Default
   private final String detail = "default detail";

   // Example of how to do optional fields, you will need to configure
   // your object mapper to support that and include the JDK 8 module in your dependencies..
   @Builder.Default
   private Optional<String> type = Optional.empty()

   @JsonPOJOBuilder(withPrefix = "")
   public static final class ErrorDetailBuilder {
   }
}

최종 필드가 있는 클래스를 역직렬화하려면 역직렬화할 최종 필드가 포함된 생성자를 선언해야 합니다.

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

private final String heading;
private final String detail;
private String type;

@JsonCreator
public ErrorDetail(@JsonProperty("heading") String heading, @JsonProperty("detail") String detail) {
    this.heading = heading;
    this.detail = detail;
}
}

또한 Mapper Feature를 사용하여 역직렬화할 때는 Mapper Feature를 사용해야 합니다.ALLOW_FINAL_FILDS_AS_MUTATORTS는 이 속성을 false로 설정합니다.

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS,false).readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

솔루션 4

  • NoArgsConstructor no no no 。 롬복으로 1.18.8 잭슨입니다.2.9.9
    @Builder
    @Getter
    @AllArgsConstructor
    public class EventDTO {

        private String id;
        private Integer isCancelled;

        private String recurringEventId;

        private String summary;
        private String description;
        private String location;
        private String startDateTime;
        private String endDateTime;

        /**
         * Make Jackson happy
         */
        public EventDTO() {
        }
    }

「」를 사용합니다.@Data내 생각에 주석은 좋지 않은 접근법이다.★★★★★★★★★★★★★를 변경해 주세요.@Data로로 합니다.@Getting,@Setter,@EqualsAndHashcode등....

도움이 된다면 여기에 적어주세요.

갱신하다

을 제안합니다.@Data@RequiredArgsConstructor, 가 없는 컨스트럭터입니다.private String type;

언급URL : https://stackoverflow.com/questions/51464720/lombok-1-18-0-and-jackson-2-9-6-not-working-together

반응형