Jackson注释
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
@ JsonIgnoreProperties
Hymanson注释用于指定要忽略的类的属性列表。 @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
@ JsonIgnoreType
Hymanson批注用于标记整个类型(类),该类型在使用该类型的任何地方都将被忽略。这是一个示例,向我们展示如何使用@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中的可见性级别匹配的常量,表示ANY
,DEFAULT
,NON_PRIVATE
,NONE
,PROTECTED_AND_PRIVATE
和PUBLIC_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
@ JsonGetter
Hymanson注释用于告诉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
@ JsonAnyGetter
Hymanson批注使我们可以将" 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
@ JsonPropertyOrder
Hymanson批注可用于指定将Java对象的字段序列化为JSON的顺序。这是显示如何使用@JsonPropertyOrder批注的示例:
@JsonPropertyOrder({"name", "personId"}) public class PersonPropertyOrder { public long personId = 0; public String name = null; }
通常,Hymanson会按照在类中找到的顺序将" PersonPropertyOrder"中的属性序列化。但是,@JsonPropertyOrder批注指定了不同的顺序,在序列化的JSON输出中,name属性将首先出现,而personId属性将第二次出现。
@JsonRawValue
@ JsonRawValue
Hymanson注释告诉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
@ JsonSerialize
Hymanson批注用于为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); } } }