[java] Jackson과 Lombok이 함께 작동하도록 만들 수 없습니다.

나는 Jackson과 Lombok을 결합하는 실험을하고 있습니다. 내 수업은 다음과 같습니다.

package testelombok;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Wither;

@Value
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
    @JsonProperty("xoom")
    private String x;
    private int z;
}
package testelombok;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xebia.jacksonlombok.JacksonLombokAnnotationIntrospector;
import java.io.IOException;

public class TestLombok {

    public static void main(String[] args) throws IOException {
        TestFoo tf = new TestFoo("a", 5);
        System.out.println(tf.withX("b"));
        ObjectMapper om = new ObjectMapper().setAnnotationIntrospector(new JacksonLombokAnnotationIntrospector());
        System.out.println(om.writeValueAsString(tf));
        TestFoo tf2 = om.readValue(om.writeValueAsString(tf), TestFoo.class);
        System.out.println(tf2);
    }

}

그것들은 내가 classpth에 추가하는 JAR입니다.

나는 그것을 Netbeans로 컴파일하고 있습니다. 위의 5 개 JAR lib은 프로젝트 폴더 내의 ” ” 폴더에 보관됩니다 ( ” src“, ” nbproject“, ” test“및 ” build“과 함께). 프로젝트 속성 의 ” Add JAR / Folder “버튼을 통해 Netbeans에 추가 했으며 위 목록과 동일한 순서로 나열됩니다. 프로젝트는 표준 “Java 애플리케이션”유형 프로젝트입니다.

또한 Netbeans 프로젝트는 ” 저장시 컴파일하지 않음 “, ” 디버깅 정보 생성 “, ” 사용되지 않는 API보고 “, ” 자바 종속성 추적 “, ” 활성화 주석 처리 “및 ” 편집기에서 주석 처리 활성화 “로 구성됩니다. Netbeans에는 주석 프로세서 또는 주석 처리 옵션이 명시 적으로 구성되어 있지 않습니다. 또한 ” -Xlint:all“명령 줄 옵션이 컴파일러 명령 줄에 전달되고 컴파일러는 외부 VM에서 실행됩니다.

내 javac의 버전은 1.8.0_72이고 Java의 버전은 1.8.0_72-b15입니다. 내 Netbeans는 8.1입니다.

내 프로젝트가 잘 컴파일됩니다. 그러나 실행시 예외가 발생합니다. 예외는 쉽게 보이거나 명백하게 고칠 수있는 것 같지 않습니다. 다음은 stacktrace를 포함한 출력입니다.

TestFoo(x=b, z=5)
{"z":5,"xoom":"a"}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
 at [Source: {"z":5,"xoom":"a"}; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:296)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:269)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:475)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3890)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3785)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)
    at testelombok.TestLombok.main(TestLombok.java:14)
Caused by: java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:511)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:323)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:253)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:219)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:141)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:406)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    ... 7 more

나는 이미 @Value@AllArgsConstructor주석으로 무작위로 찌르려고 시도했지만 더 나아질 수 없었습니다.

나는 예외를 봤고 jackson에 대한 오래된 버그 보고서열려 있지만 다른 것과 관련된 것으로 보이는 다른 버그 보고서를 발견했습니다 . 그러나 이것은 여전히이 버그가 무엇인지 또는 수정 방법에 대해 알려주지 않습니다. 또한 다른 곳에서 유용한 것을 찾을 수 없었습니다.

내가하려는 것은 lombok과 jackson의 매우 기본적인 사용법이기 때문에이 문제를 해결하는 방법에 대한 유용한 정보를 더 이상 찾을 수 없다는 것이 이상하게 보입니다. 내가 뭔가를 놓친 것일까?

롬복을 사용하지 마십시오 “또는 ” 잭슨을 사용하지 마십시오 ” 라고 말하는 것 외에 ,이 문제를 해결하는 방법에 대해 아는 사람이 있습니까?



답변

불변하지만 lombok과 jackson을 사용하는 json 직렬화 가능한 POJO를 원한다면. 롬복 빌더에서 jacksons 새 주석을 사용하십시오. @JsonPOJOBuilder(withPrefix = "")
이 솔루션을 시도했으며 매우 잘 작동합니다. 샘플 사용법

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Value;

@JsonDeserialize(builder = Detail.DetailBuilder.class)
@Value
@Builder
public class Detail {

    private String url;
    private String userName;
    private String password;
    private String scope;

    @JsonPOJOBuilder(withPrefix = "")
    public static class DetailBuilder {

    }
}

너무 많은 클래스가 @Builder있고 상용구 코드가 비어있는 주석을 원하지 않는 경우 주석 인터셉터가 비어 있도록 재정의 할 수 있습니다.withPrefix

mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
        @Override
        public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {//If no annotation present use default as empty prefix
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });

그리고 @JsonPOJOBuilder어노테이션이 있는 빈 빌더 클래스를 제거 할 수 있습니다 .


답변

Immutable + Lombok + Jackson은 다음 방법으로 달성 할 수 있습니다.

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Value;

@Value
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
public class LocationDto {

    double longitude;
    double latitude;
}

class ImmutableWithLombok {

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        String stringJsonRepresentation = objectMapper.writeValueAsString(new LocationDto(22.11, 33.33));
        System.out.println(stringJsonRepresentation);

        LocationDto locationDto = objectMapper.readValue(stringJsonRepresentation, LocationDto.class);
        System.out.println(locationDto);
    }
}


답변

나는 위의 몇 가지를 시도했지만 모두 기질이 좋았습니다. 저에게 정말로 효과가 있었던 것은 제가 여기서 찾은 답 입니다.

프로젝트의 루트 디렉토리에 lombok.config 파일을 추가 합니다 (아직 수행하지 않은 경우).

lombok.config

안에 붙여 넣으세요

lombok.anyConstructor.addConstructorProperties=true

그런 다음 다음과 같이 pojo를 정의 할 수 있습니다.

@Data
@AllArgsConstructor
public class MyPojo {

    @JsonProperty("Description")
    private String description;
    @JsonProperty("ErrorCode")
    private String errorCode;
}


답변

나는 suppressConstructorProperties = true매개 변수 를 추가하여 (귀하의 예를 사용하여) 똑같은 문제를 “해결”했습니다 .

@Value
@Wither
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestFoo {
    @JsonProperty("xoom")
    private String x;
    private int z;
}

Jackson은 분명히 java.beans.ConstructorProperties 생성자에 추가 된 주석을 좋아하지 않습니다 . suppressConstructorProperties = true매개 변수는 말한다 롬복을 (그것이 기본적으로 수행)을 추가 할 수 없습니다.


답변

@AllArgsConstructor(suppressConstructorProperties = true)더 이상 사용되지 않습니다. lombok.anyConstructor.suppressConstructorProperties=true( https://projectlombok.org/features/configuration )을 정의 하고 POJO의 롬복 주석 @Value@Data+ @NoArgsConstructor+로 변경 @AllArgsConstructor하십시오.


답변

나를 위해 lombok 버전을 ‘org.projectlombok : lombok : 1.18.0’으로 업데이트했을 때 작동했습니다.


답변

Jan Rieke의 답변에서

lombok 1.18.4부터 생성자 매개 변수에 복사 할 주석을 구성 할 수 있습니다. 이것을 당신의 lombok.config:

lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty

그런 다음 @JsonProperty필드에 추가 하십시오.

이름이 일치하더라도 모든 필드에 @JsonProperty가 필요하지만 어쨌든 따라가는 것이 좋습니다. 내가 게터보다 선호하는 이것을 사용하여 필드를 공개 최종으로 설정할 수도 있습니다.

@ToString
@EqualsAndHashCode
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
    @JsonProperty("xoom")
    public final String x;
    @JsonProperty("z")
    public final int z;
}

그래도 getter (+ setters)에서도 작동합니다.