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
在@JsonIgnoreProperties
Jackson注解用于指定一个类的属性忽略的列表。该@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;
}
在此示例中,属性firstName
和lastName
将被忽略,因为它们的名称列在@JsonIgnoreProperties
类声明上方的注释声明中。
@JsonIgnoreType
在@JsonIgnoreType
Jackson注释用来标记一个整体类型(类)处处忽视的是使用该类型。这是一个示例,向您展示如何使用@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中的可见度常数,这意味着ANY
,DEFAULT
,NON_PRIVATE
,NONE
, PROTECTED_AND_PRIVATE
和PUBLIC_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场。在我们的例子中,我们@JsonSetter
在setPersonId()
方法上方添加注释。以下是添加@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不能直接映射id
和name
财产此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
类,在@JacksonInject
该source
字段上方添加了注释:
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"));
注意如何source
在InjectableValues
addValue()
方法中设置要注入属性的值。另请注意,该值仅与类型相关联String
- 而不是与任何特定字段名称相关联。它是@JacksonInject
注释,指定要注入的值的字段。
如果您要从多个源下载人员JSON对象并为每个源注入不同的源值,则必须为每个源重复上述代码。
@JsonDeserialize
@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;
}
其次,这里是 注释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
使用类 ObjectMapper
的reader()
方法,然后我们调用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对象中使用的名称。因此,personId
JSON对象中使用的名称是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输出。如果属性是String
Jackson通常会将该值括在引号中,但如果注释@JsonRawValue
属性Jackson将不会这样做。
为了更清楚地说明了什么@JsonRawValue
,请在没有@JsonRawValue
使用的情况下查看此类:
public class PersonRawValue {
public long personId = 0;
public String address = "$#";
}
Jackson会将此序列化为此JSON字符串:
{"personId":0,"address":"$#"}
现在我们将属性添加@JsonRawValue
到address
属性中,如下所示:
public class PersonRawValue {
public long personId = 0;
@JsonRawValue
public String address = "$#";
}
Jackson现在在序列化address
财产时省略引号。序列化的JSON因此如下所示:
{"personId":0,"address":$#}
这当然是无效的JSON,那你为什么要这样呢?
好吧,如果address
属性包含一个JSON字符串,那么该JSON字符串将作为JSON对象结构的一部分序列化为最终的JSON对象,而不仅仅是address
JSON对象中字段中的字符串 。要了解这将如何工作,让我们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
的价值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);
}
}
}