Jackson注释

时间:2020-01-09 10:36:11  来源:igfitidea点击:

Hymanson JSON工具包包含一组Java批注,我们可以使用这些批注来影响将JSON读入对象的方式或者从对象生成什么JSON的方式。此Hymanson注释教程介绍了如何使用Hymanson的注释。

如果我们不熟悉Java批注,请先阅读我的Java批注教程,然后再阅读本教程。它将了解Java注释的工作方式。

读取和写入注释

Hymanson包含一组注释,这些注释会影响从JSON读取Java对象以及将Java对象写入JSON。我将这些批注称为"读+写批注"。以下各节将更详细地说明Hymanson的读和写批注。

@JsonIgnore

Hymanson批注@JsonIgnore用于告诉Hymanson忽略Java对象的某个属性(字段)。在将JSON读取到Java对象中以及将Java对象写入JSON时,都将忽略该属性。这是使用@ JsonIgnore注释的示例类:

import com.fasterxml.Hymanson.annotation.JsonIgnore;

public class PersonIgnore {

    @JsonIgnore
    public long    personId = 0;

    public String  name = null;
}

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

@JsonIgnoreProperties

@ JsonIgnorePropertiesHymanson注释用于指定要忽略的类的属性列表。 @JsonIgnoreProperties批注放置在类声明的上方,而不是要忽略的各个属性(字段)的上方。这是显示如何使用@JsonIgnoreProperties批注的示例:

import com.fasterxml.Hymanson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties({"firstName", "lastName"})
public class PersonIgnoreProperties {

    public long    personId = 0;

    public String  firstName = null;
    public String  lastName  = null;

}

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

@JsonIgnoreType

@ JsonIgnoreTypeHymanson批注用于标记整个类型(类),该类型在使用该类型的任何地方都将被忽略。这是一个示例,向我们展示如何使用@JsonIgnoreType批注:

import com.fasterxml.Hymanson.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;
}

在上面的示例中,所有"地址"实例都将被忽略。

@JsonAutoDetect

Hymanson批注@JsonAutoDetect用于告诉Hymanson在读写对象时包括不公开的属性。这是一个示例类,向我们展示如何使用@JsonAutoDetect批注:

import com.fasterxml.Hymanson.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

读注释

Hymanson包含一组注释,这些注释仅会影响Hymanson将JSON解析为对象的方式,这意味着它们会影响Hymanson对JSON的读取。我称这些为"阅读注释"。以下各节介绍了Hymanson的已读注释。

@JsonSetter

Hyman逊注解@JsonSetter用来告诉Hyman逊,当将JSON读入对象时,应将此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"
}

没有一些帮助,Hymanson无法将JSON对象的id属性映射到Java类的personId字段。

@JsonSetter批注指示Hymanson为给定的JSON字段使用setter方法。在我们的例子中,我们在setPersonId()方法上方添加了@JsonSetter注释。这是添加@ 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

Hymanson批注@JsonAnySetter指示Hymanson为JSON对象中所有无法识别的字段调用相同的setter方法。 "无法识别"是指尚未映射到Java对象中的属性或者设置方法的所有字段。看一下这个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"
}

Hymanson无法直接将此JSON对象的id和name属性映射到Bag类,因为Bag类不包含任何公共字段或者setter方法。

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

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

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

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

@JsonCreator

Hymanson注释" @JsonCreator"用于告诉Hymanson 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;
    }

}

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

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

}

请注意,构造函数上方的注释以及构造函数参数之前的注释。现在,Hymanson能够从此JSON对象创建一个" PersonImmutable":

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

@Hymanson

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

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

public class PersonInject {

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

    @HymansonInject
    public String source = null;

}

为了让Hymanson将值注入到source字段中,我们在创建HymansonObjectMapper时需要做一些额外的工作。这是让Hymanson将值注入Java对象的过程:

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

请注意,如何在InjectableValuesaddValue()方法中设置要注入source属性的值。还要注意,该值仅与类型String绑定,而与任何特定字段名称无关。@ HymansonInject注释指定了将值注入到哪个字段。

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

@JsonDeserialize

Hymanson批注@JsonDeserialize用于为Java对象中给定的字段指定自定义反序列化器类。例如,假设我们想将布尔值" false"和" true"的在线格式优化为" 0"和" 1"。

首先,我们需要在要使用自定义反序列化器的字段中添加@JsonDeserialize批注。这是在字段中添加@JsonDeserialize批注的样子:

public class PersonDeserialize {

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

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

其次,这是从@JsonDeserialize批注中引用的OptimizedBooleanDeserializer类的样子:

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类扩展了具有通用类型Boolean的JsonDeserializer类。这样做会使deserialize()方法返回一个布尔对象。如果要反序列化其他类型(例如java.util.Date),则必须在泛型括号内指定该类型(如果我们不熟悉Java泛型,我也有Java泛型教程)。

我们可以通过调用jsonParser参数的getText()方法来获取要反序列化的字段的值。然后,我们可以将该文本反序列化为任何值,然后输入反序列化程序所针对的类型(在此示例中为" Boolean")。

最后,我们需要查看使用自定义反序列化器和@ JsonDeserializer注释反序列化对象的外观:

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

注意,我们首先需要如何使用ObjectMapper的reader()方法为PersonDeserialize类创建一个读取器,然后在该方法返回的对象上调用readValue()。

写注释

Hymanson还包含一组注释,这些注释可以影响Hymanson将Java对象序列化(写入)到JSON的方式。这些写入(序列化)注释中的每一个都将在以下各节中介绍。

@JsonInclude

Hymanson的注解@JsonInclude告诉Hymanson在某些情况下仅包含属性。例如,仅当属性为非null,非空或者具有非默认值时,才应包括该属性。这是显示如何使用@JsonInclude批注的示例:

import com.fasterxml.Hymanson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {

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

}

如果为该示例设置的值是非空的,则此示例将仅包含" name"属性,即不为null且不是空字符串。

@JsonInclude注解的一个更能说的名字可能是@JsonIncludeOnlyWhen,但是写起来会更长。

@JsonGetter

@ JsonGetterHymanson注释用于告诉Hymanson,应该通过调用getter方法而不是通过直接字段访问来获取某个字段值。如果Java类使用jQuery样式的getter和setter名称,则@JsonGetter批注很有用。例如,可以使用方法personId()和personId(long id)来代替getPersonId()和setPersonId()。

这是一个名为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对象中使用的名称。因此,用于JSON对象中的" personId"的名称为" id"。生成的JSON对象将如下所示:

{"id":0}

还要注意,对personId(long personId)方法进行了注解,并使用了@JsonSetter注释,以使Hymanson识别为与JSON对象中的id属性匹配的设置方法。从JSON读取到Java对象时使用@JsonSetter批注,而不是在将Java对象写入JSON时使用。为了完整起见,仅包含了@JsonSetter注释。

@JsonAnyGetter

@ JsonAnyGetterHymanson批注使我们可以将" Map"用作要序列化为JSON的属性的容器。这是在Java类中使用@ JsonAnyGetter注释的示例:

public class PersonAnyGetter {

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

    @JsonAnyGetter
    public Map<String, Object> properties() {
        return properties;
    }
}

当看到@JsonAnyGetter注释时,Hymanson将获得从@JsonAnyGetter注释的方法返回的Map,并将该Map中的每个键值对都视为一个属性。换句话说,"映射"中的所有键值对都将作为" PersonAnyGetter"对象的一部分序列化为JSON。

@JsonPropertyOrder

@ JsonPropertyOrderHymanson批注可用于指定将Java对象的字段序列化为JSON的顺序。这是显示如何使用@JsonPropertyOrder批注的示例:

@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {

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

}

通常,Hymanson会按照在类中找到的顺序将" PersonPropertyOrder"中的属性序列化。但是,@JsonPropertyOrder批注指定了不同的顺序,在序列化的JSON输出中,name属性将首先出现,而personId属性将第二次出现。

@JsonRawValue

@ JsonRawValueHymanson注释告诉Hymanson该属性值应直接写入JSON输出。如果该属性为String,则Hymanson通常会将值括在引号中,但如果使用@@ JsonRawValue`属性进行注释,Hymanson将不会这样做。

为了更清楚地说明@ JsonRawValue的作用,请看没有使用@@ JsonRawValue`的此类:

public class PersonRawValue {

    public long   personId = 0;

    public String address  = "$#";
}

Hymanson会将其序列化为以下JSON字符串:

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

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

public class PersonRawValue {

    public long   personId = 0;

    @JsonRawValue
    public String address  = "$#";
}

现在,当对" address"属性进行序列化时,Hymanson将省略引号。因此,序列化的JSON如下所示:

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

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

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

public class PersonRawValue {

    public long   personId = 0;

    @JsonRawValue
    public String address  =
            "{ \"street\" : \"Wall Street\", \"no\":1}";

}

Hymanson会将其序列化为以下JSON:

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

请注意,JSON字符串现在如何成为序列化JSON结构的一部分。

没有@ JsonRawValue批注,Hymanson会将对象序列化为以下JSON:

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

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

@JsonValue

Hymanson的注解@JsonValue告诉Hymanson,Hyman逊不应该尝试序列化对象本身,而应该在对象上调用将对象序列化为JSON字符串的方法。请注意,Hymanson将在自定义序列化返回的String内转义任何引号,因此我们不能返回例如完整的JSON对象。为此,我们应该改用@ JsonRawValue(请参阅上一节)。

@ JsonValue注释被添加到Hymanson调用以将对象序列化为JSON字符串的方法中。这是显示如何使用@JsonValue注解的示例:

public class PersonValue {

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

    @JsonValue
    public String toJson(){
        return this.personId + "," + this.name;
    }

}

让Hyman逊序列化一个" PersonValue"对象所得到的输出是这样的:

"0,null"

引号由Hymanson添加。请记住,对象返回的值字符串中的所有引号均会转义。

@JsonSerialize

@ JsonSerializeHymanson批注用于为Java对象中的字段指定自定义序列化程序。这是一个使用@JsonSerialize注释的Java类示例:

public class PersonSerializer {

    public long   personId = 0;
    public String name     = "John";

    @JsonSerialize(using = OptimizedBooleanSerializer.class)
    public boolean enabled = false;
}

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

" OptimizedBooleanSerializer"会将" true"值序列化为" 1",将" false"值序列化为" 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);
        }
    }
}