programing

잭슨과 롬복에게 함께 일하게 할 수 없다.

newsource 2022. 10. 27. 21:52

잭슨과 롬복에게 함께 일하게 할 수 없다.

나는 잭슨과 롬복의 결합을 실험하고 있다.제 수업은 다음과 같습니다.

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은 다음과 같습니다.

  • Lombok: https://projectlombok.org/downloads/lombok.jar (버전 1.16.10)

  • 잭슨 주석: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.2/jackson-annotations-2.8.2.jar

  • 잭슨 코어: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.2/jackson-core-2.8.2.jar

  • 잭슨 데이터바인드: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.2/jackson-databind-2.8.2.jar

  • Jackson-lombok

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입니다.넷콩은 8.1입니다.

내 프로젝트는 잘 정리되어 있다.그러나 실행 시 예외가 발생합니다.이 예외는 쉽게 또는 명백하게 수정 가능한 것으로 보이는 것은 아닌 것 같습니다.스택 트레이스를 포함한 출력을 다음에 나타냅니다.

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주석을 달았지만 더 이상 나아지게 할 수는 없었어요

예외를 검색해 보니 잭슨에 대한 오래된 버그 보고서와 열려있지만 다른 것과 관련이 있는 것 같습니다.단, 이 버그의 개요나 수정 방법에 대해서는 아직 알 수 없습니다.그리고 다른 곳에서는 쓸만한 것을 찾을 수 없었다.

제가 하려고 하는 것은 lombok과 jackson 둘 다 매우 기본적인 사용법이기 때문에, 이 문제를 어떻게 해결할지에 대한 유용한 정보를 찾을 수 없었던 것이 이상하다고 생각합니다.내가 뭘 놓쳤나?

"롬복 쓰지 마" "잭슨 쓰지"라고 말하는 것 말고, 이 문제를 해결할 방법을 알고 있는 사람?

불변하지만 롬복과 잭슨을 사용한 json 시리얼화 POJO를 원한다면.합니다.@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석입니니다다

불변+롬복+잭슨은 다음 방법으로 달성할 수 있습니다.

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;
}

주석을 사용한 예를 다음에 나타냅니다.

import lombok.Value;
import lombok.Builder;
import lombok.extern.jackson.Jacksonized;

@Jacksonized
@Builder
@Value
public class User {
    private final String name;
    private final String surname;
}

「」를 사용할 .@Builder석입니니다다

문제를 그것을 '해결'해서 '.이 문제를 해결하려면suppressConstructorProperties = true파예예예예 ( 예예::: ) :

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

잭슨은 컨스트럭터에 주석을 추가하는 것을 좋아하지 않는 것 같습니다.suppressConstructorProperties = true파라미터는 Lombok에게 추가하지 않도록 지시합니다(기본값으로 추가).

할 수 은 두 가 있습니다.@Builder잭슨이랑 같이.

옵션 1

  • 개인 기본 noArgs 및 allArgs 컨스트럭터를 추가합니다.
@Builder
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Person {

    @JsonProperty("user_name")
    private String name;
}

옵션 2

이 기사 덕분에.

잭슨은 빌더 방식이 다음과 같이 시작되기를 기대합니다..withProperty(...)에서는 지지 but but but but but but but but가 생성됩니다..property(...).

작성자 클래스를 직접 만들어 잭슨 주석을 추가할 수 있습니다.그런 다음 Lombok은 이 클래스를 재사용하고 모든 빌더 메서드를 추가합니다.

@JsonDeserialize(builder = MyDto.MyDtoBuilder.class)
@Builder
@Getter
public class MyDto {

    @JsonProperty("user_id")
    private String userId;

    @JsonPOJOBuilder(withPrefix = "")
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class MyDtoBuilder {
    }
}
  • 너는 수작업이 필요하다.
  • 빌더를 직접 쓰는 것보다 훨씬 낫습니다.
  • 이 에도 ''와 같은 이 있다는 점에 해 주세요.@JsonIgnorePropertie

으로 리팩터의 을 바꾸지 입니다.MyDtoBuilderLombok/Jackson은 Lombok/Jackson이다.

업데이트: 옵션 1에 추가된 다른 솔루션(lombok 1.18.20 및 스프링 부트 2.4.5에서 테스트됨)이 발견되었습니다.

추가 주석 없이 더 단순하게 수행할 수 있으며 상속이 문제일 수 있습니다. 즉, 하위 클래스도 역직렬화 가능해야 합니다.예를 들어 다음과 같습니다.

요건:

lombok.config프로젝트 루트 디렉토리 내에는 다음 내용을 포함하는 본문이 있습니다.

lombok.anyConstructor.addConstructorProperties=true
/** The parent class **/

@Value
@NonFinal
@SuperBuilder
@RequiredArgsConstructor
public class Animal {
  String name;
}

/** The child class **/

@Value
@SuperBuilder
@RequiredArgsConstructor
public class Cat {
  Long tailLength;
  
  @ConstructorProperties({"tailLength", "name})
  public Cat(Long tailLength, String name) {
      super(name);
      this.tailLength = tailLength;
  }
}

그 내용:

  1. 부모 필드를 포함한 오브젝트 작성 가능
  2. 「」로 .ObjectMapper 잭슨은
  3. 상위 클래스 및 하위 클래스의 인스턴스는 변경할 수 없습니다.

다른 예에 대한 나의 조언:

  1. 특정 클래스에 사용자 지정 주석을 배치하지 마십시오. 그러면 클래스가 불균일해집니다.어쨌든, 언젠가는 범용 솔루션에 도달하게 될 것입니다.
  2. JacksonJackson이 주석 없이 직렬화/비직렬화를 수행할 수 있는 경우 생성자의 모든 필드에 주석을 달면 커플링이 생성됩니다.
  3. 「 」를하지 주세요.@AllArgsConstructor불변의 실체를 위해.클래스에 최종 필드만 있는 경우 개념적으로 올바른 것은@RequiredArgsConstructor이렇게 하면 클래스 클래스가 항상 불변의 엔티티를 가진 컨스트럭터에만 의존할 수 있습니다.@AllArgsConstructor을 사용하다

@AllArgsConstructor(suppressConstructorProperties = true)을 사용하다의 정의lombok.anyConstructor.suppressConstructorProperties=true(https://projectlombok.org/features/configuration)에서 POJO의 롬복 주석을 변경합니다.@Value로로 합니다.@Data+@NoArgsConstructor+@AllArgsConstructor잘 먹히네요.

얀 리케의 대답에서

1.4 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;
}

단, getters(+setters)에서도 동작합니다.

롬복 버전을 'org.projectlombok:lombok:1.18.0'으로 업데이트 했을 때 동작했습니다.

이 롬복 주석을 사용하여 클래스를 불변하게 유지하고 역직렬화 할 수 있었습니다.

@NoArgsConstructor(force = true)

"믹신" 패턴을 사용하면 잭슨이 어떤 것이든 가지고 놀 수 있습니다.기본적으로 잭슨 주석을 기존 클래스에 추가할 때 클래스를 실제로 변경하지 않아도 됩니다.Rombok 솔루션보다는 이 솔루션을 추천하는 것이 Jackson의 기능에서 발생하는 문제를 해결했기 때문에 장기간에 걸쳐 기능할 가능성이 높기 때문에 이 솔루션을 추천하는 것이 좋습니다.

모든 수업에서 다음과 같은 주석을 달았습니다.

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor

롬복과 잭슨의 모든 버전에서 최소 몇 년 동안 작동했습니다.

예:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    String id;
    String first;
    String last;
}

그리고 이것이 마지막입니다.롬복과 잭슨은 부적처럼 함께 논다.

Gson을 사용하는 것은 번거롭지 않기 때문에 추천합니다.

스프링 부트 앱에 추가했습니다.

spring.mvc.converters.preferred-json-mapper=gson

메이븐의 의존성과 함께 모든 문제를 해결했습니다.나는 롬복 주석 포조스를 수정할 필요가 없었다.

@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
   String id;
   String first;
   String last;
}

데이터 클래스 외에 ObjectMapper를 올바르게 구성해야 합니다.이 경우 ParameterNamesModule 설정으로 정상적으로 동작하며 필드 및 Creator 메서드의 가시성을 설정합니다.

    om.registerModule(new ParameterNamesModule());
    om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY);
    om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);

그럼 예상대로 되겠네요.

이 Lombok을 하지 않도록 데 .ConstructorProperies어노테이션은 반대로 되어 잭슨이 그 어노테이션을 볼 수 없게 되었다.

범인은 Jackson Annotation입니다.내성자님.find Creator Annotation 입니다.주의:

if (_cfgConstructorPropertiesImpliesCreator
            && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)

Jackson Annotation도 주의해 주세요.내성자님.setConstructorPropertiesImpliesCreator:

public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
{
    _cfgConstructorPropertiesImpliesCreator = b;
    return this;
}

두 옵션 중 할 수 .MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIESJacksonAnnotationIntrospector 설정하다setConstructorPropertiesImpliesCreator로로 합니다.false 설정해 주세요.AnnotationIntrospectorObjectMapper오브젝트 맵퍼 경유.set 주석내성자님.

Jackson 8., 그 에서는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.잭슨 2.8.10입니다.MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES을 사용하다나는 그것이 잭슨의 어떤 버전에서 추가되었는지 확실하지 않다.없는 경우에는 '아예'를 합니다.JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator메카니즘.

이 모듈도 필요합니다.https://github.com/FasterXML/jackson-modules-java8

그런 다음 컴파일러의 -parameters 플래그를 켭니다.

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>

저도 잠시 고생했어요.그러나 이 문서를 보면 onConstructor 주석 파라미터는 실험적인 것으로 간주되며 IDE(STS 4)에서는 잘 지원되지 않습니다.잭슨 문서에 따르면 개인 구성원은 기본적으로 직렬화되지 않습니다.이 문제를 신속하게 해결할 수 있는 방법이 있습니다.

JsonAutoDetect 주석을 추가하고 보호된 멤버/개인 멤버를 감지하도록 적절하게 설정합니다.이것은 DTO에게 편리합니다.

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class SomeClass

@JsonCreator 주석을 사용하여 공장 함수를 추가합니다. 이 기능은 객체 검증 또는 추가 변환이 필요한 경우에 가장 적합합니다.

public class SomeClass {

   // some code here

   @JsonCreator
   public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
      return new SomeClass();
   }
}

물론 직접 컨스트럭터를 추가할 수도 있습니다.

나에게 효과가 있는 옵션

  • 콩에 @AllArgsConstructor를 넣는 것만으로 효과가 있었습니다.
  • mapper.configure(MapperFeature)를 추가합니다.ACCEPT_CASE_INSECTIVE_PROPERTIES, true). 오브젝트 매퍼 인스턴스.

나는 다른 문제를 가지고 있었는데 그것은 부울 프리미티브 타입에 관한 것이었다.

private boolean isAggregate;

그 결과 다음과 같은 오류가 발생했습니다.

Exception: Unrecognized field "isAggregate" (class 

이 Lambok을 변환합니다.isAggregate로로 합니다.isAggregate()로서 롬복의 내부 재산을 만드는 게터로서aggregate, ★★★★★★★★★★★★★★★★」isAggregate잭슨 도서관이 싫어해서isAggregate대신 속성을 지정합니다.

이 문제를 해결하기 위해 원시 부울을 래퍼 부울로 업데이트했습니다.에도 이 문제를 다룰 때는 가지 이 있습니다.booleantypes 를 해 주세요types, "types" 를 해 주세요.

솔:

private Boolean isAggregate;

참조: https://www.baeldung.com/lombok-getter-boolean

언급URL : https://stackoverflow.com/questions/39381474/cant-make-jackson-and-lombok-work-together