@JsonProperty属性在什么情况下使用,它有什么作用?

286

这个bean叫做'State':

public class State {

    private boolean isSet;

    @JsonProperty("isSet")
    public boolean isSet() {
        return isSet;
    }

    @JsonProperty("isSet")
    public void setSet(boolean isSet) {
        this.isSet = isSet;
    }

}

使用ajax的'success'回调函数将其发送到网络:

        success : function(response) {  
            if(response.State.isSet){   
                alert('success called successfully)
            }

这里需要使用 @JsonProperty 注解吗?使用它有什么优势?我认为我可以删除这个注解而不会产生任何副作用。

https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations 上阅读有关此注释的信息,但我不知道何时需要使用它。


4
好的,我会尽力进行翻译。以下是您需要翻译的内容:http://www.baeldung.com/jackson-annotations - Archmede
9个回答

344

这里有一个很好的例子。我用它来重命名变量,因为JSON是从一个.Net环境中获取的,该环境中属性以大写字母开头。

public class Parameter {
  @JsonProperty("Name")
  public String name;
  @JsonProperty("Value")
  public String value; 
}

这个正确地解析为/从JSON中:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}

1
字符串成员变量不能重命名为正确的大小写吗?例如,public String name; 可以改为 public String Name; 吗? - blue-sky
25
可以,但在Java环境下这会不符合编码标准。这更多是我的追求完美而非真正的编码问题,但它是一个很好、简单的例子来展示@JsonProperty注释的实际用途。 - OldCurmudgeon
4
是的,类型无关紧要,这只影响名称。 - OldCurmudgeon
1
@Pavan - 这与命名无关。我猜你应该检查你的设置器(setters)。 - OldCurmudgeon
@OldCurmudgeon,您能否提供给我示例代码呢? - Pavan
显示剩余4条评论

62

我认为OldCurmudgeon和StaxMan都是正确的,但这里有一个简单示例的一句话答案。

@JsonProperty(name)告诉Jackson ObjectMapper将JSON属性名称映射到带注释的Java字段的名称。

//example of json that is submitted 
"Car":{
  "Type":"Ferrari",
}

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }

类名应该与 JSON 的根元素相同吗?这对我不起作用。 - Pavan

50

就它的价值而言,JsonProperty不仅用于指定普通的序列化和反序列化,还用于指定变量的getter和setter方法。例如,假设您有这样一个有效载荷:

{
  "check": true
}

还需要一个反序列化类:

public class Check {

  @JsonProperty("check")    // It is needed else Jackson will look got getCheck method and will fail
  private Boolean check;

  public Boolean isCheck() {
     return check;
  }
}

那么在这种情况下,需要使用JsonProperty注释。然而,如果您的类中还有一个方法

public class Check {

  //@JsonProperty("check")    Not needed anymore
  private Boolean check;

  public Boolean getCheck() {
     return check;
  }
}

请查看此文档: http://fasterxml.github.io/jackson-annotations/javadoc/2.13/com/fasterxml/jackson/annotation/JsonProperty.html


30

没有注释的话,从JSON中匹配出来的属性名将是"set",而不是本意似乎是"isSet"。这是因为根据Java Beans规范,形如"isXxx"和"setXxx"的方法被认为是有逻辑属性"xxx"需要管理。


4
这个是针对问题所给出的具体情况的正确答案。 - Andrew Spencer

12

你知道,这都是关于对象的序列化和反序列化。假设有一个对象:

public class Parameter {
  public String _name;
  public String _value; 
}

该对象的序列化结果为:

{
  "_name": "...",
  "_value": "..."
}

变量名直接用于序列化数据。如果您要从系统实现中删除系统API,则在某些情况下,您必须重命名序列化/反序列化中的变量。 @JsonProperty是元数据,用于告诉序列化程序如何序列化对象。它用于:

  • 变量名称
  • 访问(读取,写入)
  • 默认值
  • 必需/可选

例如:

public class Parameter {
  @JsonProperty(
        value="Name",
        required=true,
        defaultValue="No name",
        access= Access.READ_WRITE)
  public String _name;
  @JsonProperty(
        value="Value",
        required=true,
        defaultValue="Empty",
        access= Access.READ_WRITE)
  public String _value; 
}

11

添加JsonProperty还可以确保安全性,以防某人决定更改其中一个属性名称,而不知道涉及的类将被序列化为Json对象。如果他们更改了属性名称,JsonProperty将确保它将在Json对象中使用,而不是属性名称。


10
除了以上所有的答案,不要忘记文档中提到的部分:
标记注释可用于将非静态方法定义为逻辑属性的“setter”或“getter”(取决于其签名),或用作逻辑属性的非静态对象字段(序列化、反序列化)。
如果您的类中有一个非传统的非静态方法不是常规的getter或setter,那么您可以使用该注释使其像getter和setter一样运行。请参见以下示例
public class Testing {
    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIdAndUsername() {
        return id + "." + username; 
    }

    public String concatenateIdAndUsername() {
        return id + "." + username; 
    }
}
当上述对象被序列化时,响应将包含:
- getUsername() 返回的用户名 - getId() 返回的 ID - getIdAndUsername() 返回的 idAndUsername* 由于方法getIdAndUsername()get开头,因此它被视为普通的getter,因此可以用@JsonIgnore进行注释。
如果你注意到concatenateIdAndUsername()没有被返回,那是因为它的名称不以get开头。如果希望该方法的结果包含在响应中,则可以使用@JsonProperty("..."),并按照上面突出显示的文档中所述,将其视为正常的getter/setter

7
作为其他答案的补充,如果您在没有无参构造函数的类中使用@JsonCreator注释,则@JsonProperty注释非常重要。
public class ClassToSerialize {

    public enum MyEnum {
        FIRST,SECOND,THIRD
    }

    public String stringValue = "ABCD";
    public MyEnum myEnum;


    @JsonCreator
    public ClassToSerialize(MyEnum myEnum) {
        this.myEnum = myEnum;
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        ClassToSerialize classToSerialize = new ClassToSerialize(MyEnum.FIRST);
        String jsonString = mapper.writeValueAsString(classToSerialize);
        System.out.println(jsonString);
        ClassToSerialize deserialized = mapper.readValue(jsonString, ClassToSerialize.class);
        System.out.println("StringValue: " + deserialized.stringValue);
        System.out.println("MyEnum: " + deserialized.myEnum);
    }
}

在这个例子中,唯一的构造函数被标记为@JsonCreator,因此Jackson将使用这个构造函数创建实例。但输出结果是这样的:

序列化:{"stringValue":"ABCD","myEnum":"FIRST"}

异常信息: thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of ClassToSerialize$MyEnum from String value 'stringValue': value not one of declared Enum instance names: [FIRST, SECOND, THIRD]

但是在构造函数中添加了@JsonProperty注释后:
@JsonCreator
public ClassToSerialize(@JsonProperty("myEnum") MyEnum myEnum) {
    this.myEnum = myEnum;
}

反序列化成功:

序列化结果: {"myEnum":"FIRST","stringValue":"ABCD"}

字符串值: ABCD

枚举值: FIRST


1

从JsonProperty javadoc来看,

定义逻辑属性的名称,即用于该属性的JSON对象字段名。如果值是空字符串(默认值),将尝试使用已注释的字段的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接