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

Ori*_*ski 90 java serialization json jackson

在Jackson中,当你用一个构造函数注释时@JsonCreator,你必须用它来注释它的参数@JsonProperty.所以这个构造函数

public Point(double x, double y) {
    this.x = x;
    this.y = y;
}
Run Code Online (Sandbox Code Playgroud)

成为这个:

@JsonCreator
public Point(@JsonProperty("x") double x, @JsonProperty("y") double y) {
    this.x = x;
    this.y = y;
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这是必要的.你能解释一下吗?

Luk*_*tor 95

Jackson必须知道将JSON对象中的字段传递给构造函数的顺序.使用反射无法访问Java中的参数名称 - 这就是您必须在注释中重复此信息的原因.

  • @MariuszS这是真的,但是[post](http://stackoverflow.com/a/32272061/271149)解释了如何在Java8编译器标志和Jackson模块的帮助下摆脱无关的注释.我已经测试了这种方法并且它有效. (11认同)
  • 这对Java8无效 (5认同)

Rod*_*ada 46

Java代码在运行时通常无法访问参数名称(因为它被编译器删除),因此如果您需要该功能,则需要使用Java 8的内置功能或使用诸如ParaNamer之类的库来获取访问权限它.

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

杰克逊模块参数名称

使用Java 8时,此模块允许您获取无注释的构造函数参数.要使用它,首先需要注册模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());
Run Code Online (Sandbox Code Playgroud)

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

javac -parameters ...
Run Code Online (Sandbox Code Playgroud)

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

杰克逊模块-paranamer

另一个只需要您注册模块或配置注释内省(但不是注释中指出的两者).它允许您在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());
Run Code Online (Sandbox Code Playgroud)

链接:https://github.com/FasterXML/jackson-modules-base/tree/master/paranamer


Man*_*dis 25

可以使用jdk8避免构造函数注释,其中编译器可选地引入具有构造函数参数名称的元数据.然后使用jackson-module-parameter-names模块,Jackson可以使用这个构造函数.你可以在没有注释的杰克逊后面看到一个例子


let*_*nka 11

可以简单地使用 java.bean.ConstructorProperties 注释 - 它不那么冗长,杰克逊也接受它。例如 :

  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;
  }
Run Code Online (Sandbox Code Playgroud)

  • 非常好的收获,我无法以其他方式找到:所以,不依赖于 Jackson API 并且更简洁! (2认同)

lcf*_*cfd 6

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


Smu*_*tje 5

当我正确理解这一点时,您可以将默认构造函数替换为参数化构造函数,因此必须描述用于调用构造函数的 JSON 键。