jackson是java中最常用的json處理工具包之一,其他類似功能的包括gson和fastjson等。本文將簡單介紹jackson的基礎(chǔ)知識(shí),以作為各位讀者未來使用的參考。
三種使用方式
jackson有三種處理json的方式,分別為
- data binding
- tree model
- streaming api
data binding
這種方式可以在json字符串和pojo對(duì)象之間直接進(jìn)行轉(zhuǎn)換。比如說我們有一個(gè)json字符串
{"firstName":"dizzy","lastName":"dwarf"}
通過這種方式我們可以直接將其轉(zhuǎn)換成一個(gè)Person類的實(shí)例,其中firstName和lastName是Person類定義的兩個(gè)成員變量。
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(jsonStr, Person.class);
tree model
這種方式類似于xml的DOM解析,在json字符串和DOM樹之間進(jìn)行轉(zhuǎn)換,DOM樹的節(jié)點(diǎn)是JsonNode類型。其優(yōu)點(diǎn)在于以統(tǒng)一的方式看待json字符串中的各個(gè)部分,使用起來更靈活。
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(jsonStr);
JsonNode firstName = root.path("firstName");
構(gòu)建DOM樹
如何構(gòu)建JsonNode的DOM樹呢?JsonNode是抽象類,需要使用ObjectNode和ArrayNode等子類。
ObjectNode objectNode = objectMapper.createObjectNode();
ArrayNode arrayNode = objectMapper.createArrayNode();
streaming api
這種方式類似于xml的SAX解析,每次處理一個(gè)事件,或者這里叫token更合適。
streaming api反序列化
反序列化用的是JsonParser,它的使用方式和迭代器非常相似。你每次處理的都是一個(gè)token,比如說在上面這個(gè)json字符串中,包括{、firstName、dizzy、lastName、dwarf、}等6個(gè)token,通過調(diào)用nextToken方法可以獲得下一個(gè)token。
streaming api序列化
序列化用的JsonGenerator,它的方法都非常直觀,比如說writeStartObject、writeStringField、writeEndObject等,這里就不具體介紹了。
注解
通過注解可以定制jackson的各種特性,這里只介紹最常用的幾個(gè)。
序列化注解
-
@JsonGetter
注解在方法上,將方法返回的值作為字段序列化的值
public class Person {
private String firstName;
@JsonGetter("firstName")
public String getFirstName() {
return firstName + "_modified";
}
// 省略了setter方法
}
這樣一個(gè)firstName為"dizzy"的Person序列化后就變成了
{"firstName":"dizzy_modified"}
-
@JsonSerialize
注解在成員變量上,使用指定的JsonSerializer實(shí)現(xiàn)類來序列化這個(gè)字段,這個(gè)實(shí)現(xiàn)類最關(guān)鍵的是serialize方法,這個(gè)方法會(huì)為你提供JsonGenerator對(duì)象作為參數(shù),讓你可以通過它來構(gòu)建序列化后的值。 -
@JsonValue
注解在方法上,將方法返回的值作為整個(gè)對(duì)象序列化的結(jié)果。
反序列化注解
-
@JsonSetter
@JsonGetter的逆過程 -
@JsonDeserialize
@JsonSerialize的逆過程 -
@JsonAlias
默認(rèn)情況下java對(duì)象中的成員變量名和json字符串的字段名是一對(duì)一關(guān)系的,但是可能存在這樣一種情況。比如firstName這個(gè)成員變量,可能json字符串有不同的來源,有的地方這個(gè)字段叫firstName,另外一些地方傳的字段名稱是fName。這個(gè)時(shí)候就可以用@JsonAlias使這個(gè)成員變量接受更多的名稱。
通用注解
-
@JsonProperty
指定該成員變量對(duì)應(yīng)的json字符串的字段名,默認(rèn)情況下如果兩者相同的話不需要使用該注解。 -
@JsonIgnore
指定該成員變量不參與序列化和反序列化
具體問題解決
下劃線和駝峰轉(zhuǎn)換
一般情況下java變量命名采用駝峰方式,而json字符串可能采用下劃線方式。解決方式為在類或者成員變量上增加以下注解
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
需要注意的是雖然反序列化的時(shí)候first_name會(huì)對(duì)應(yīng)到firstName變量,但是序列化的時(shí)候也會(huì)輸出為first_name
多態(tài)處理
有時(shí)候我們希望根據(jù)json字符串中某個(gè)字段的取值反序列化成不同的子類,比如說type為1是Student,type為2是Teacher,注意Student和Teacher必須繼承同一個(gè)父類Person。
@JsonTypeInfo(use = JsonTypeInfo.ID.NAME, property = "type", defaultImpl = Person.class)
@JsonSubTypes({
@JsonSubTypes.Type(value = Student.class, name = "1"),
@JsonSubTypes.Type(value = Teacher.class, name = "2")
})
public class Person {}
- property是決定子類型的字段名稱
- defaultImpl是默認(rèn)情況下反序列化的類型,這里指的是當(dāng)type不為1和2時(shí)
- name是子類型對(duì)應(yīng)的字段取值
帶泛型參數(shù)的List和Map的反序列化
如果我們希望ObjectMapper.readValue返回List<Person>或者M(jìn)ap<String, Person>,由于List<Person>.class和Map<String, Person>.class在java中是不合法的,需要借助于TypeReference
TypeReference<List<Person>> typeReference = new TypeReference<List<Person>>(){};
List<Person> list = objectMapper.readValue(jsonStr, typeReference);
jackson如何集成Spring
Spring提供的MappingJackson2MessageConverter類封裝了ObjectMapper,如果希望對(duì)ObjectMapper進(jìn)行定制,可以自己生成一個(gè)MappingJackson2MessageConverter對(duì)象并注冊(cè)為bean
只對(duì)部分成員變量序列化同時(shí)不影響反序列化
有時(shí)候我們希望只對(duì)部分成員變量進(jìn)行序列化,如果用@JsonIgnore,會(huì)同時(shí)影響反序列化。這個(gè)時(shí)候我們可以用@JsonView注解指定某個(gè)視圖類的序列化結(jié)果包含該成員變量。