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입니다.
Lombok : https://projectlombok.org/downloads/lombok.jar (버전 1.16.10)
Jackson 주석 : 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
Jackson databind : http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.2/jackson-databind-2.8.2.jar
Jackson-lombok : http://repo1.maven.org/maven2/io/paradoxical/jackson-lombok/1.1/jackson-lombok-1.1.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
어노테이션이 있는 빈 빌더 클래스를 제거 할 수 있습니다 .
나는 suppressConstructorProperties = true
매개 변수 를 추가하여 (귀하의 예를 사용하여) 똑같은 문제를 "해결"했습니다 .
@Value
@Wither
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestFoo {
@JsonProperty("xoom")
private String x;
private int z;
}
Jackson은 분명히 java.beans.ConstructorProperties
생성자에 추가 된 주석을 좋아하지 않습니다 . suppressConstructorProperties = true
매개 변수는 말한다 롬복을 (그것이 기본적으로 수행)을 추가 할 수 없습니다.
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);
}
}
@AllArgsConstructor(suppressConstructorProperties = true)
더 이상 사용되지 않습니다. lombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration )을 정의 하고 POJO의 롬복 주석 @Value
을 @Data
+ @NoArgsConstructor
+로 변경 @AllArgsConstructor
하십시오.
나는 위의 몇 가지를 시도했지만 모두 기질이 좋았습니다. 저에게 정말로 효과가 있었던 것은 제가 여기서 찾은 답 입니다.
프로젝트의 루트 디렉토리에 파일을 추가하십시오 (아직 수행하지 않은 경우).
lombok.config
안에 붙여 넣으세요
lombok.anyConstructor.addConstructorProperties=true
그런 다음 다음과 같이 pojo를 정의 할 수 있습니다.
@Data
@AllArgsConstructor
public class MyPojo {
@JsonProperty("Description")
private String description;
@JsonProperty("ErrorCode")
private String errorCode;
}
나를 위해 lombok 버전을 'org.projectlombok : lombok : 1.18.0'으로 업데이트했을 때 작동했습니다.
"mixin"패턴 을 사용하면 Jackson이 거의 모든 것을 가지고 놀 수 있습니다 . 기본적으로 클래스를 실제로 수정하지 않고 기존 클래스에 Jackson 주석을 추가하는 방법을 제공합니다. 잭슨이 Jackson 기능에 대해 가지고있는 문제를 해결하기 때문에 Lombok 솔루션보다는 여기에서 권장하는쪽으로 기울고 있습니다. 따라서 장기적으로 작동 할 가능성이 더 큽니다.
이 모듈도 필요합니다. 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>
나는 모든 수업에 다음과 같이 주석을 달았습니다.
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
적어도 2 년 동안 모든 Lombok 및 Jackson 버전에서 작동했습니다.
예:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person {
String id;
String first;
String last;
}
그리고 그게 다야. 롬복과 잭슨은 마치 매력처럼 함께 연주합니다.
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
String id;
String first;
String last;
}
데이터 클래스 외에 ObjectMapper를 올바르게 구성해야합니다. 이 경우 ParameterNamesModule 구성으로 정상적으로 작동하고 필드 및 생성자 메서드의 가시성을 설정합니다.
om.registerModule(new ParameterNamesModule());
om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY);
om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
그러면 예상대로 작동합니다.
나는 ConstructorProperies
주석을 추가하지 않도록 Lombok을 얻는 데 문제가 있었기 때문에 반대 방향으로 가서 Jackson이 주석을 볼 수 없도록했습니다.
범인은 JacksonAnnotationIntrospector.findCreatorAnnotation 입니다. 주의:
if (_cfgConstructorPropertiesImpliesCreator
&& config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
Also notice JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator:
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
{
_cfgConstructorPropertiesImpliesCreator = b;
return this;
}
So two options, either set the MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
to false or create a JacksonAnnotationIntrospector
set setConstructorPropertiesImpliesCreator
to false
and set this AnnotationIntrospector
into the ObjectMapper
via ObjectMapper.setAnnotationIntrospector.
Notice a couple things, I am using Jackson 2.8.10 and in that version MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
does not exist. I am not sure in which version of Jackson it was added. So if it is not there, use the JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
mechanism.
I struggled with this for a moment as well. But looking through the documentation here I can see that the onConstructor annotation parameter is considered experimental and is not supported well on my IDE (STS 4). According to the Jackson documentation, private members are not (de)serialized by default. There are quick ways to resolve this.
Add JsonAutoDetect annotation and set it appropriately to detect protected/private members. This is convenient for DTOs
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class SomeClass
Add a factory function with @JsonCreator annotation, this works best if you need some object validation or additional transforms.
public class SomeClass {
// some code here
@JsonCreator
public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
return new SomeClass();
}
}
Of course you could just manually add the constructor in yourself also as well.
Since lombok 1.18.4, you can configure what annotations are copied to the constructor parameters. Insert this into your
lombok.config
:lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
Then just add
@JsonProperty
to your fields:...
You'll need a @JsonProperty on every field even if the name matches, but that is a good practice to follow anyway. You can also set your fields to public final using this, which I prefer over getters.
@ToString
@EqualsAndHashCode
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
@JsonProperty("xoom")
private final String x;
@JsonProperty("z")
private final int z;
}
Try adding a @NoArgsConstructor
I had a different issue and it was with the boolean primitive types.
private boolean isAggregate;
It was throwing the following error as a result
Exception: Unrecognized field "isAggregate" (class
Lambok converts isAggregate
to isAggregate()
as a getter making the property internally to lombok as aggregate
instead isAggregate
. The Jackson library doesn't like it and it needs isAggregate
property instead.
I updated the primitive boolean to Wrapper Boolean to work around this issue. There are other options for you if you are dealing with boolean
types, see the reference below.
Sol:
private Boolean isAggregate;
ref: https://www.baeldung.com/lombok-getter-boolean
ReferenceURL : https://stackoverflow.com/questions/39381474/cant-make-jackson-and-lombok-work-together
'programing' 카테고리의 다른 글
제공되지 않은 필수 매개 변수에 사용할 HTTP 상태 코드는 무엇입니까? (0) | 2021.01.15 |
---|---|
React Native 앱을 브라우저에서 테스트 할 수 있습니까? (0) | 2021.01.15 |
머리글과 바닥 글 div 사이의 모든 공간을 채우기 위해 div를 만드는 방법 (0) | 2021.01.15 |
첫 번째 앱 업데이트, 사용자 데이터 손실 (문서 디렉토리에 저장 됨) (0) | 2021.01.15 |
git repo를 두 번째 컴퓨터로 이동 하시겠습니까? (0) | 2021.01.15 |