【问题标题】: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;
}

我不明白为什么它是必要的。能解释一下吗?

【问题讨论】:

    标签: java json serialization jackson


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      正如annotation documentation中所说的,注解表明参数名称被用作属性名称,不做任何修改,但可以指定为非空值以指定不同的名称:

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 这对 Java8 无效
        • @MariuszS 这是真的,但是这个post 解释了如何在Java8 编译器标志和Jackson 模块的帮助下摆脱无关注释。我已经测试了这种方法并且它有效。
        • 当然,像魅力一样工作:) docs.oracle.com/javase/tutorial/reflect/member/…
        【解决方案4】:

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

        【讨论】:

        【解决方案5】:

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

        【讨论】:

        【解决方案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;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-02-23
          • 1970-01-01
          • 1970-01-01
          • 2021-11-04
          • 2018-04-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多