为什么用@JsonCreator 注释构造函数时,其参数必须用@JsonProperty 注释?

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

我不明白为什么有这个必要,你能解释一下吗?

140947 次浏览

如果我正确理解了 这个,你可以用一个参数化的缺省构造函数代替它,因此必须描述用来调用构造函数的 JSON 键。

正如在 注释文件中所精确说明的那样,注释表明参数名称被用作属性名称,没有任何修改,但是可以将其指定为非空值来指定不同的名称:

Jackson 必须知道将字段从 JSON 对象传递到构造函数的顺序。 使用反射访问 Java 中的参数名称是不可能的——这就是为什么您必须在注释中重复这些信息的原因。

因为 Java 字节码不保留方法或构造函数参数的名称。

使用 jdk8可以避免构造函数注释,编译器可以选择引入带有构造函数参数名称的元数据。然后与 Jackson 模块参数名模块杰克逊可以使用这个构造函数。您可以在后面的 没有注释的杰克逊中看到一个示例

Java 代码在运行时通常不能访问参数名(因为它被编译器删除了) ,所以如果你想要那个功能,你需要使用 Java 8的内置功能或者使用像 ParaNamer 这样的库来访问它。

因此,为了在使用 Jackson 时不必为构造函数参数使用注释,您可以使用以下两个 Jackson 模块中的任何一个:

Jackson 模块参数名

这个模块允许您在使用 爪哇8时获得无注释的构造函数参数。为了使用它,你首先需要注册模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());

然后使用-reference 标志编译代码:

javac -parameters ...

链接: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

杰克逊模块

另一种方法只需要注册模块或配置注释自省(但不是注释中指出的两种方法)。它允许您在 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

人们可以简单地使用 java.bean. structorProperties 注释——它不那么冗长,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;
}

只要偶然发现它并在某个地方得到答案。你可以从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;
}
}