为啥构造函数用@JsonCreator注解时,它的参数必须用@JsonProperty注解?
Posted
技术标签:
【中文标题】为啥构造函数用@JsonCreator注解时,它的参数必须用@JsonProperty注解?【英文标题】:Why when a constructor is annotated with @JsonCreator, its arguments must be annotated with @JsonProperty?为什么构造函数用@JsonCreator注解时,它的参数必须用@JsonProperty注解? 【发布时间】:2014-03-22 03:18:00 【问题描述】:在 Jackson 中,当您使用 @JsonCreator
注释构造函数时,您必须使用 @JsonProperty
注释其参数。所以这个构造函数
public Point(double x, double y)
this.x = x;
this.y = y;
变成这样:
@JsonCreator
public Point(@JsonProperty("x") double x, @JsonProperty("y") double y)
this.x = x;
this.y = y;
我不明白为什么它是必要的。能解释一下吗?
【问题讨论】:
【参考方案1】:当我正确理解 this 时,您将默认构造函数替换为参数化构造函数,因此必须描述用于调用构造函数的 JSON 键。
【讨论】:
【参考方案2】:正如annotation documentation中所说的,注解表明参数名称被用作属性名称,不做任何修改,但可以指定为非空值以指定不同的名称:
【讨论】:
【参考方案3】:Jackson 必须知道将字段从 JSON 对象传递到构造函数的顺序。 在 Java 中使用反射无法访问参数名称 - 这就是您必须在注释中重复此信息的原因。
【讨论】:
这对 Java8 无效 @MariuszS 这是真的,但是这个post 解释了如何在Java8 编译器标志和Jackson 模块的帮助下摆脱无关注释。我已经测试了这种方法并且它有效。 当然,像魅力一样工作:) docs.oracle.com/javase/tutorial/reflect/member/…【参考方案4】:因为 Java 字节码不保留方法或构造函数参数的名称。
【讨论】:
不再正确:docs.oracle.com/javase/tutorial/reflect/member/… @MariuszS 确实如此,但由于这是一个新的(非默认编译器标志),Jackson 将不得不继续支持其@JsonProperty
注释【参考方案5】:
使用 jdk8 可以避免构造函数注释,其中编译器将可选地引入带有构造函数参数名称的元数据。然后通过jackson-module-parameter-names 模块杰克逊可以使用这个构造函数。你可以在帖子Jackson without annotations看到一个例子
The Java™ Tutorials - Obtaining Names of Method Parameters【讨论】:
已弃用并移至jackson-modules-java8/parameter-names【参考方案6】:Java 代码在运行时通常无法访问参数名称(因为它是由编译器删除的),因此,如果您想要该功能,您需要使用 Java 8 的内置功能或使用诸如 ParaNamer 之类的库。访问它。
因此,为了在使用 Jackson 时不必为构造函数参数使用注释,您可以使用以下两个 Jackson 模块中的任何一个:
杰克逊模块参数名称
此模块允许您在使用 Java 8 时获取无注释的构造函数参数。为了使用它,您首先需要注册模块:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());
然后使用 -parameters 标志编译您的代码:
javac -parameters ...
链接:https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names
杰克逊模块参数
另外一个只需要您注册模块或配置注释自省(但并非如 cmets 所指出的那样)。它允许您在 1.8 之前的 Java 版本上使用无注释的构造函数参数。
ObjectMapper mapper = new ObjectMapper();
// either via module
mapper.registerModule(new ParanamerModule());
// or by directly assigning annotation introspector (but not both!)
mapper.setAnnotationIntrospector(new ParanamerOnJacksonAnnotationIntrospector());
链接:https://github.com/FasterXML/jackson-modules-base/tree/master/paranamer
【讨论】:
Paranamer 模块似乎比 ParameterNames 好得多:它不需要 Java 8,也不需要-parameters
编译器标志。你知道有什么缺点吗?【参考方案7】:
可以简单地使用 java.bean.ConstructorProperties 注释 - 它不那么冗长,Jackson 也接受它。例如:
import java.beans.ConstructorProperties;
@ConstructorProperties("answer","closed","language","interface","operation")
public DialogueOutput(String answer, boolean closed, String language, String anInterface, String operation)
this.answer = answer;
this.closed = closed;
this.language = language;
this.anInterface = anInterface;
this.operation = operation;
【讨论】:
非常好的捕获,我无法找到其他方法:因此,不依赖于 Jackson API 并且不那么冗长!【参考方案8】:只是遇到它并在某处得到答案。从 2.7.0 开始你可以使用下面的注解
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Point
final private double x;
final private double y;
@ConstructorProperties("x", "y")
public Point(double x, double y)
this.x = x;
this.y = y;
【讨论】:
以上是关于为啥构造函数用@JsonCreator注解时,它的参数必须用@JsonProperty注解?的主要内容,如果未能解决你的问题,请参考以下文章
注解有啥作用,啥时候用注解。Java中怎么样实现注解的构造函数