Jackson的注解

Jackson JSON工具包包含一组Java注释,您可以使用它们来影响如何将JSON读入对象,或者从对象生成JSON。

Read + Write注释

既影响从JSON读取Java对象,也影响将Java对象写入JSON的注解,称为“读取+写入注释”。以下部分更详细地解释了Jackson的读写注释。

@JsonIgnore

Jackson注释@JsonIgnore用于告诉Jackson忽略Java对象的某个属性(字段)。将JSON读入Java对象时,以及将Java对象写入JSON时,都会忽略该属性。示例:

import com.fasterxml.jackson.annotation.JsonIgnore; 
public class PersonIgnore { 
     @JsonIgnore 
     public long personId = 0; 
     public String name = null;
 }

在上面的类中,personId不会从JSON读取属性或将属性写入JSON。

@JsonIgnoreProperties

@JsonIgnorePropertiesJackson注解用于指定一个类的属性忽略的列表。该@JsonIgnoreProperties注释被置于上面的类声明,而不是上面的个人属性(字段),以忽略。示例 :

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 
 @JsonIgnoreProperties({“firstName”,“lastName”}) 
public class PersonIgnoreProperties { 
     public long personId = 0; 
     public String firstName = null;
     public String lastName = null; 
 }

在此示例中,属性firstNamelastName将被忽略,因为它们的名称列在@JsonIgnoreProperties类声明上方的注释声明中。

@JsonIgnoreType

@JsonIgnoreTypeJackson注释用来标记一个整体类型(类)处处忽视的是使用该类型。这是一个示例,向您展示如何使用@JsonIgnoreType 注释:

import com.fasterxml.jackson.annotation.JsonIgnoreType; 
public class PersonIgnoreType { 
    @JsonIgnoreType 
    public static class Address { 
        public String streetName = null; 
        public String houseNumber = null; 
        public String zipCode = null; 
        public String city = null; 
        public String country = null; 
    } 
     public long PERSONID = 0; 
     public String name = null; 
     public Address address = null; 
 }

在上面的示例中,Address将忽略所有实例。

@JsonAutoDetect

Jackson注释@JsonAutoDetect用于告诉Jackson在Read和Write对象时包含非公开的属性。示例:

import com.fasterxml.jackson.annotation.JsonAutoDetect; 
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) 
public class PersonAutoDetect { 
    private long personId = 123; 
    public String name = null; 
}

JsonAutoDetect.Visibility类包含匹配Java中的可见度常数,这意味着ANYDEFAULTNON_PRIVATENONEPROTECTED_AND_PRIVATEPUBLIC_ONLY

Read注释

只会影响Jackson如何将JSON解析为对象的注解称为“读取注释”。以下部分介绍了Jackson的阅读注释。

@JsonSetter

@JsonSetter在将JSON读入对象时 ,Jackson注释用于告诉Jackson应该将此setter方法的名称与JSON数据中的属性名称相匹配。如果Java类中内部使用的属性名称与JSON文件中使用的属性名称不同,则此选项很有用。

以下Person类使用personId其id属性的名称:

public class Person {

    private long   personId = 0;
    private String name     = null;

    public long getPersonId() { return this.personId; }
    public void setPersonId(long personId) { this.personId = personId; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

但在此JSON对象中,使用名称id而不是personId

{
  "id"   : 1234,
  "name" : "John"
}

如果没有一些帮助,Jackson无法将id属性从JSON对象映射到personId Java类的字段。
@JsonSetter注释指导Jackson使用setter方法对于给定的JSON场。在我们的例子中,我们@JsonSettersetPersonId()方法上方添加注释。以下是添加@JsonSetter注释的方式:

public class Person {

    private long   personId = 0;
    private String name     = null;

    public long getPersonId() { return this.personId; }
    @JsonSetter("id")
    public void setPersonId(long personId) { this.personId = personId; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

@JsonSetter注释中 指定的值是与此setter方法匹配的JSON字段的名称。在这种情况下,名称是id因为这是我们要映射到setPersonId()setter方法的JSON对象中的字段的名称。

@JsonAnySetter

Jackson注释@JsonAnySetter指示Jackson为JSON对象中的所有无法识别的字段调用相同的setter方法。“无法识别”是指所有尚未映射到Java对象中的属性或setter方法的字段。看看这Bag堂课:

public class Bag {

    private Map<String, Object> properties = new HashMap<>();

    public void set(String fieldName, Object value){
        this.properties.put(fieldName, value);
    }

    public Object get(String fieldName){
        return this.properties.get(fieldName);
    }
}

然后看看这个JSON对象:

{
  "id"   : 1234,
  "name" : "John"
}

Jackson不能直接映射idname财产此JSON对象到的 Bag类,因为Bag类不包含公共字段或setter方法。

您可以set()通过添加@JsonAnySetter注释告诉Jackson 为所有无法识别的字段调用该方法 ,如下所示:

public class Bag {

    private Map<String, Object> properties = new HashMap<>();

    @JsonAnySetter
    public void set(String fieldName, Object value){
        this.properties.put(fieldName, value);
    }

    public Object get(String fieldName){
        return this.properties.get(fieldName);
    }
}

现在,Jackson将set()使用JSON对象中所有无法识别的字段的名称和值调用该方法。

请记住,这仅对无法识别的字段有影响。例如,如果您向Java类添加了公共name 属性或setName(String)方法Bag,那么name JSON对象中的字段将映射到该属性/ setter。

@JsonCreator

Jackson注释@JsonCreator用于告诉Jackson Java对象有一个构造函数(“创建者”),它可以将JSON对象的字段与Java对象的字段进行匹配。

@JsonSetter的注释不能使用, @JsonCreator在注释中就是十分有用。例如,不可变对象没有任何setter方法,因此需要将它们的初始值注入构造函数中。以这个PersonImmutable类为例:

public class PersonImmutable {

    private long   id   = 0;
    private String name = null;

    public PersonImmutable(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

要告诉Jackson它应该调用构造函数,PersonImmutable我们必须将@JsonCreator 注释添加到构造函数中。但仅凭这一点还不够。我们还必须注释构造函数的参数,以告诉Jackson哪些JSON对象的字段传递给哪些构造函数参数。以下是 PersonImmutable类添加@JsonCreator@JsonProperty注释的外观:

public class PersonImmutable {

    private long   id   = 0;
    private String name = null;

    @JsonCreator
    public PersonImmutable(
            @JsonProperty("id")  long id,
            @JsonProperty("name") String name  ) {

        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

请注意构造函数上方的注释和构造函数参数之前的注释。现在Jackson能够PersonImmutable从这个JSON对象创建一个:

{
  "id"   : 1234,
  "name" : "John"
}

@JacksonInject

@JacksonInject用于将值注入已解析的对象,而不是从JSON中读取这些值。例如,假设您正在从各种不同的源下载人JSON对象,并且想知道给定的人对象来自哪个源。原JSON可能不包含该信息,但您可以让Jackson将其注入到从JSON对象创建的Java对象中。

要将Java类中的字段标记为需要由Jackson注入其值@JacksonInject的字段,请在该字段上方添加 注释。这是一个示例PersonInject类,在@JacksonInjectsource字段上方添加了注释:

public class PersonInject {

    public long   id   = 0;
    public String name = null;

    @JacksonInject
    public String source = null;

}

为了让Jackson在source场上注入价值,你需要在创造杰克逊时多做一点ObjectMapper。以下是将Jackson注入Java对象所需的内容:

InjectableValues inject = new InjectableValues.Std().addValue(String.class, "jenkov.com");
PersonInject personInject = new ObjectMapper().reader(inject)
                        .forType(PersonInject.class)
                        .readValue(new File("data/person.json"));

注意如何sourceInjectableValues addValue()方法中设置要注入属性的值。另请注意,该值仅与类型相关联String- 而不是与任何特定字段名称相关联。它是@JacksonInject注释,指定要注入的值的字段。

如果您要从多个源下载人员JSON对象并为每个源注入不同的源值,则必须为每个源重复上述代码。

@JsonDeserialize

@JsonDeserialize用于为Java对象中的给定字段指定自定义反序列化器类。例如,假设你想优化布尔值的上了线的格式falsetrue01

首先,您需要将@JsonDeserialize注释添加到要使用自定义反序列化器的字段中。以下是将@JsonDeserialize注释添加到字段的方式如下:

public class PersonDeserialize {

    public long    id      = 0;
    public String  name    = null;

    @JsonDeserialize(using = OptimizedBooleanDeserializer.class)
    public boolean enabled = false;
}

其次,这里是 注释OptimizedBooleanDeserializer引用的@JsonDeserialize类:

public class OptimizedBooleanDeserializer extends JsonDeserializer<Boolean> {

    @Override
    public Boolean deserialize(JsonParser jsonParser,
            DeserializationContext deserializationContext) throws
        IOException, JsonProcessingException {

        String text = jsonParser.getText();
        if("0".equals(text)) return false;
        return true;
    }
}

请注意,OptimizedBooleanDeserializer该类JsonDeserializer以泛型类型扩展Boolean。这样做会使deserialize()方法返回一个Boolean 对象。如果要反序列化另一种类型(例如a java.util.Date),则必须在泛型括号内指定该类型。
通过调用参数的getText()方法 获取要反序列化的字段的值jsonParser。然后,您可以将该文本反序列化为您的反序列化程序所针对的任何值和类型(Boolean在此示例中为a)。
最后,您需要查看使用自定义反序列化器和@JsonDeserializer注释反序列化对象的样子 :

PersonDeserialize person = objectMapper
        .reader(PersonDeserialize.class)
        .readValue(new File("data/person-optimized-boolean.json"));

注意,我们首先需要创建为读者PersonDeserialize使用类 ObjectMapperreader()方法,然后我们调用readValue() 由该方法返回的对象。

Write注释

影响Jackson如何将Java对象序列化(写入)到JSON的注解叫Write注释。

@JsonInclude

Jackson的注释@JsonInclude告诉Jackson只在某些情况下包括属性。例如,仅当属性为非null,非空或具有非默认值时,才应包含该属性。以下是一个示例,说明如何使用@JsonInclude注释:

import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {
    public long  personId = 0;
    public String name     = null;
}

此示例仅包含name属性,如果为其设置的值为非空,意味着不为null且不是空字符串。
这个@JsonInclude注释的名称本来可以@JsonIncludeOnlyWhen,但是编写的时间会更长。

@JsonGetter

@JsonGetter注释是用来告诉Jackson某一个字段值应该从调用来获得getter方法,而不是通过直接字段访问。的@JsonGetter ,如果您的Java类使用jQuery的风格的getter和setter名称注释是有用的。例如,代替 getPersonId()setPersonId()你可能有方法personId()personId(long id)
这是一个名为的示例类PersonGetter,它显示了@JsonGetter注释的用法 :

public class PersonGetter {
    private long  personId = 0;
    @JsonGetter("id")
    public long personId() { return this.personId; }
    @JsonSetter("id")
    public void personId(long personId) { this.personId = personId; }
}

如您所见,该personId()方法使用注释进行@JsonGetter注释。@JsonGetter注释上设置的值是应该在JSON对象中使用的名称。因此,personIdJSON对象中使用的名称是id。生成的JSON对象如下所示:

{
    "id":0
}

另请注意,该personId(long personId)方法使用注释进行@JsonSetter 注释,以使Jackson识别出id与JSON对象中的属性匹配的setter 。在@JsonSetter不写Java对象到JSON的时候-从JSON读入的Java对象时注解使用。该@JsonSetter注释只是为了保持完整性的缘故。

@JsonAnyGetter

@JsonAnyGetter可以使用Map作为要序列化JSON性容器。以下是@JsonAnyGetter在Java类中使用注释的示例:

public class PersonAnyGetter {
    private Map<String, Object> properties = new HashMap<>();
    @JsonAnyGetter
    public Map<String, Object> properties() {
        return properties;
    }
}

当看到@JsonAnyGetter注释时,Jackson将从注释Map的方法中获取返回的内容,并将其中的@JsonAnyGetter每个键值对 Map视为属性。换句话说,Map将把所有键值对序列化为JSON作为PersonAnyGetter对象的一部分。

@JsonPropertyOrder

@JsonPropertyOrder杰克逊注解可以应用在哪些命令你的Java对象的字段应该序列化为JSON指定。以下是显示如何使用@JsonPropertyOrder 注释的示例:

@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {
    public long  personId  = 0;
    public String name     = null;
}

通常,Jackson会PersonPropertyOrder根据他们在课堂上发现的顺序对属性进行序列化。但是,@JsonPropertyOrder注释指定了一个不同的顺序,其中name属性将首先出现,而personId属性在序列化JSON输出中为第二个。

@JsonRawValue

@JsonRawValue注解告诉Jackson,这个属性的值应该直接写,因为它是对JSON输出。如果属性是StringJackson通常会将该值括在引号中,但如果注释@JsonRawValue属性Jackson将不会这样做。

为了更清楚地说明了什么@JsonRawValue,请在没有@JsonRawValue 使用的情况下查看此类:

public class PersonRawValue {

    public long   personId = 0;

    public String address  = "$#";
}

Jackson会将此序列化为此JSON字符串:

{"personId":0,"address":"$#"}

现在我们将属性添加@JsonRawValueaddress属性中,如下所示:

public class PersonRawValue {
    public long   personId = 0;
    @JsonRawValue
    public String address  = "$#";
}

Jackson现在在序列化address财产时省略引号。序列化的JSON因此如下所示:

{"personId":0,"address":$#}

这当然是无效的JSON,那你为什么要这样呢?

好吧,如果address属性包含一个JSON字符串,那么该JSON字符串将作为JSON对象结构的一部分序列化为最终的JSON对象,而不仅仅是addressJSON对象中字段中的字符串 。要了解这将如何工作,让我们address像这样更改属性的值 :

public class PersonRawValue {
    public long   personId = 0;
    @JsonRawValue
    public String address  =
            "{ \"street\" : \"Wall Street\", \"no\":1}";
}

Jackson会把这个序列化为这个JSON:

{"personId":0,"address":{ "street" : "Wall Street", "no":1}}

注意JSON字符串现在是序列化JSON结构的一部分。
如果没有@JsonRawValue注释,Jackson会将对象序列化为此JSON:

{"personId":0,"address":"{ \"street\" : \"Wall Street\", \"no\":1}"}

请注意address属性的值现在如何用引号括起来,并且值内的所有引号都被转义。

@JsonValue

@JsonValue告诉Jackson不应该尝试序列化对象本身,而是在对象上调用一个方法,将对象序列化为JSON字符串。请注意,Jackson将转义自定义序列化返回的String内的任何引号,因此您无法返回例如完整的JSON对象。为此,您应该使用@JsonRawValue(参见上一节)。

@JsonValue注释被添加到杰克逊是调用该对象序列化到一个JSON字符串的方法。以下是显示如何使用@JsonValue注释的示例:

public class PersonValue {
    public long   personId = 0;
    public String name = null;
    @JsonValue
    public String toJson(){
        return this.personId + "," + this.name;
    }
}

要求Jackson序列化PersonValue对象的输出是这样的:

"0,null"

引号由Jackson添加。请记住,对象返回的值字符串中的任何引号都将被转义。

@JsonSerialize

@JsonSerialize注释用于在Java对象指定一个字段的自定义序列。以下是使用@JsonSerialize注释的示例Java类:

public class PersonSerializer {
    public long   personId = 0;
    public String name     = "John";
    @JsonSerialize(using = OptimizedBooleanSerializer.class)
    public boolean enabled = false;
}

注意字段@JsonSerialize上方的注释enabled

OptimizedBooleanSerializer将序列化true的价值1false价值0。这是代码:

public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {

    @Override
    public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator, 
        SerializerProvider serializerProvider) 
    throws IOException, JsonProcessingException {

        if(aBoolean){
            jsonGenerator.writeNumber(1);
        } else {
            jsonGenerator.writeNumber(0);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值