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

时间:2014-02-20 21:49:15

标签: java json serialization jackson

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

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

8 个答案:

答案 0 :(得分:90)

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

答案 1 :(得分:41)

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

杰克逊模块-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());

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

答案 2 :(得分:23)

可以使用jdk8避免构造函数注释,其中编译器可选地引入具有构造函数参数名称的元数据。然后使用jackson-module-parameter-names模块,Jackson可以使用此构造函数。您可以在帖子Jackson without annotations

上看到示例

答案 3 :(得分:6)

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

答案 4 :(得分:3)

当我正确理解this时,用参数化的构造函数替换默认构造函数,因此必须描述用于调用构造函数的JSON键。

答案 5 :(得分:3)

annotation documentation中精确定位时,注释指示参数名称用作属性名称而不进行任何修改,但可以将其指定为非空值以指定不同的名称:

答案 6 :(得分:0)

一个人可以简单地使用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;
  }

答案 7 :(得分:0)

只要碰到它并在某个地方得到答案即可。您可以从2.7.0开始使用以下注释

class MyDict1(models.Model):
_name='my_module.my_dict1'

name=fields.Char()
child_ids=fields.One2many('my_module.my_dict2', 'parent_id')


class MyDict2(models.Model):
_name='my_module.my_dict2'

name=fields.Char()
parent_id=fields.Many2one('my_module.my_dict1')
child_ids=fields.One2many('my_module.my_dict3', 'parent_id')