不能让jackson和龙目岛一起工作
我正在尝试结合jackson和龙目岛。 这些是我的课程:
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:
-
龙目岛: 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
-
jackson核心: 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进行编译(我不认为这是真的相关,但无论如何我都要报告这一点,以使其完美且忠实地再现)。 上面的五个JAR保存在项目文件夹中名为“ lib
”的文件夹中(以及“ src
”,“ nbproject
”,“ test
”和“ build
”)。 我通过项目属性中的“ 添加JAR /文件夹 ”按钮将它们添加到Netbeans中,它们按照上面列表的确切顺序列出。 该项目是标准的“Java应用程序”类型项目。
此外,Netbeans项目配置为“ 不保存时编译 ”,“ 生成调试信息 ”,“ 报告已弃用的API ”,“ 跟踪java依赖项 ”,“ 激活注释过程 ”和“ 在编辑器中激活注释过程 ”。 Netbeans中未明确配置注释处理器或注释处理选项。 此外,“- -Xlint:all
”命令行选项在编译器命令行中传递,编译器在外部VM上运行。
我的javac版本是1.8.0_72,我的java版本是1.8.0_72-b15。 我的Netbeans是8.1。
我的项目编译得很好。 但是,它会在执行时抛出exception。 exception似乎不是任何容易或明显可修复的东西。 这是输出,包括堆栈跟踪:
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的旧bug报告 , 另一个是开放的,但似乎与其他东西有关 。 但是,这仍然没有说明这个错误是什么或如何解决它。 此外,我找不到任何其他有用的东西。
因为我想要做的是lombok和jackson的非常基本的用法,我似乎找不到有关如何解决这个问题的更多有用信息似乎很奇怪。 也许我错过了什么?
除了说“ 不要使用lombok ”或“ 不要使用jackson ”之外,有没有人知道如何解决这个问题?
如果你想使用lombok和jackson的不可变但是json可序列化的POJO。 在你的lomboks构建器@JsonPOJOBuilder(withPrefix = "")
上使用jacksons new注释@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
参数告诉Lombok不要添加它(默认情况下它)。
不推荐使用@AllArgsConstructor(suppressConstructorProperties = true)
。 定义lombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration )并将POJO的@Value
注释从@Value
为@Data
+ @NoArgsConstructor
+ @AllArgsConstructor
适合我。
如果你使用“mixin”模式,你可以让Jackson玩几乎任何东西。 基本上,它为您提供了一种方法,可以将Jackson注释添加到现有类中,而无需实际修改该类。 我倾向于在这里推荐它而不是Lombok解决方案,因为这解决了jackson在Jacksonfunction方面遇到的问题,所以它更有可能长期工作。
你也需要这个模块。 https://github.com/FasterXML/jackson-modules-java8
然后打开编译器的-parameters标志。
org.apache.maven.plugins maven-compiler-plugin 3.7.0 -parameters
对我来说,当我将lombok版本更新为:’org.projectlombok:lombok:1.18.0’时,它才有用
我的所有课程都注释如下:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor
它至少在几年内与所有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; }
就是这样。 龙目岛和jackson一起玩耍就像一个魅力。
@JsonInclude(JsonInclude.Include.NON_NULL) @Data public class Person { String id; String first; String last; }
除了Data Class之外,它应该正确配置ObjectMapper。 在这种情况下,它可以正常使用ParameterNamesModule配置,并设置Fields和Creator Methods的可见性
om.registerModule(new ParameterNamesModule()); om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY); om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
然后它应该按预期工作。
我遇到了让Lombok不添加ConstructorProperies
注释的问题,所以走了另一条道路并禁止Jackson查看该注释。
罪魁祸首是JacksonAnnotationIntrospector.findCreatorAnnotation 。 注意:
if (_cfgConstructorPropertiesImpliesCreator && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
另请注意JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator :
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b) { _cfgConstructorPropertiesImpliesCreator = b; return this; }
因此有两个选项,要么将MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
设置为false,要么将JacksonAnnotationIntrospector
设置为setConstructorPropertiesImpliesCreator
为false
并通过ObjectMapper.setAnnotationIntrospector将此AnnotationIntrospector
设置为ObjectMapper 。
注意一些事情,我使用的是Jackson 2.8.10,在那个版本中MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
不存在。 我不确定它添加了哪个版本的Jackson。 因此,如果不存在,请使用JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
机制。