1. 程式人生 > 實用技巧 >Jackson 高階應用

Jackson 高階應用

目錄


轉自:https://www.ibm.com/developerworks/cn/java/jackson-advanced-application/index.html

格式處理(含日期格式)


不同型別的日期型別,Jackson 的處理方式也不同。

  • 對於日期型別為 java.util.Calendar,java.util.GregorianCalendar,java.sql.Date,java.util.Date,java.sql.Timestamp,若不指定格式, 在 json 檔案中將序列化 為 long 型別的資料。顯然這種預設格式,可讀性差,轉換格式是必要的。Jackson 有 很多方式轉換日期格式。
  • 註解方式,請參照" Jackson 的註解的使用"的@ JsonFormat 的示例。
  • ObjectMapper 方式,呼叫 ObjectMapper 的方法 setDateFormat,將序列化為指定格式的 string 型別的資料。
  • 對於日期型別為 java.time.LocalDate,還需要新增程式碼 mapper.registerModule(new JavaTimeModule()),同時新增相應的依賴 jar 包

清單 1 . JSR31 0 的配置資訊

<dependency> 
<groupId>com.fasterxml.jackson.datatype</groupId> 
<artifactId>jackson-datatype-jsr310</artifactId> 
<version>2.9.1</version> 
</
dependency>

對於 Jackson 2.5 以下版本,需要新增程式碼 objectMapper.registerModule(new JSR310Module ())

  • 對於日期型別為 org.joda.time.DateTime,還需要新增程式碼 mapper.registerModule(new JodaModule()),同時新增相應的依賴 jar 包

清單 2. joda 的 配置資訊

<dependency> 
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId> 
<version>2.9.1</version> 
</dependency>

泛型反序列化


Jackson 對泛型反序列化也提供很好的支援。

  • 對於 List 型別 ,可以呼叫 constructCollectionType 方法來序列化,也可以構造 TypeReference 來序列化。

清單 1 . List 泛 型使用示例

CollectionType javaType = mapper.getTypeFactory() 
.constructCollectionType(List.class, Person.class); 
List<Person> personList = mapper.readValue(jsonInString, javaType); 
List<Person> personList = mapper.readValue(jsonInString, new
   TypeReference<List<Person>>(){});

清單 2 . Map 泛型使用示例

//第二引數是 map 的 key 的型別,第三引數是 map 的 value 的型別 
 MapType javaType =
    mapper.getTypeFactory().constructMapType(HashMap.class,String.class,
    Person.class); 
 Map<String, Person> personMap = mapper.readValue(jsonInString,
    javaType); 
 Map<String, Person> personMap = mapper.readValue(jsonInString, new
    TypeReference<Map<String, Person>>() {});

屬性視覺化


是 java 物件的所有的屬性都被序列化和反序列化,換言之,不是所有屬性都視覺化,預設的屬性視覺化的規則如下:

  • 若該屬性修飾符是 public,該屬性可序列化和反序列化。
  • 若屬性的修飾符不是 public,但是它的 getter 方法和 setter 方法是 public,該屬性可序列化和反序列化。因為 getter 方法用於序列化, 而 setter 方法用於反序列化。
  • 若屬性只有 public 的 setter 方法,而無 public 的 getter 方 法,該屬性只能用於反序列化。

若想更改預設的屬性視覺化的規則,需要呼叫 ObjectMapper 的方法 setVisibility。

下面的示例使修飾符為 protected 的屬性 name 也可以序列化和反序列化。

清單 1 . 屬性視覺化示例

mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); 
 public class Person { 
public int age; 
 protected String name; 
} 
 PropertyAccessor 支援的型別有 ALL,CREATOR,FIELD,GETTER,IS_GETTER,NONE,SETTER 
 Visibility 支援的型別有 A
    NY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PUBLIC,PUBLIC_ONLY

屬性過濾


在將 Java 物件序列化為 json 時 ,有些屬性需要過濾掉,不顯示在 json 中 , Jackson 有多種實現方法。

  • 註解方式, 可以用 @JsonIgnore 過濾單個屬性或用 @JsonIgnoreProperties 過濾多個屬性,示例如下:

清單 1 . 屬性過濾示例一

@JsonIgnore 
public int getAge() 
@JsonIgnoreProperties(value = { "age","birth_date" }) 
public class Person
  • addMixIn 方法加註解方式@JsonIgnoreProperties。

addMixIn 方法簽名如下:

public ObjectMapper addMixIn(Class<?> target, Class<?> mixinSource);

addMixIn 方法的作用是用 mixinSource 介面或類的註解會重寫 target 或 target 的子型別的註解。 用ixIn 設定

Person peixIn 的 @JsonIgnoreProperties("name")所重寫,最終忽略的屬性為 name,最終生成的 json 如下:

{"birthDate":"2017/09/13","age":40}

  • SimpleBeanPropertyFilter 方式。這種方式比前兩種方式更加靈活,也更復雜一些。

首先需要設定@JsonFilter 類或介面,其次設定 addMixIn,將@JsonFilter 作用於 java 物件上,最後呼叫 SimpleBeanPropertyFilter 的 serializeAllExcept 方法或重寫 S impleBeanPropertyFilter 的 serializeAsField 方法來過濾相關屬性。示例如下:

清單 2 . 屬性過濾示例三

//設定 Filter 類或介面 
 @JsonFilter("myFilter") 
public interface MyFilter {} 
//設定 addMixIn 
mapper.addMixIn(Person.class, MyFilter.class); 
//呼叫 SimpleBeanPropertyFilter 的 serializeAllExcept 方法 
 SimpleBeanPropertyFilter newFilter = 
 SimpleBeanPropertyFilter.serializeAllExcept("age"); 
//或重寫 SimpleBeanPropertyFilter 的 serializeAsField 方法 
 SimpleBeanPropertyFilter newFilter = new SimpleBeanPropertyFilter() { 
 @Override 
 public void serializeAsField(Object pojo, JsonGenerator jgen, 
 SerializerProvider provider, PropertyWriter writer) 
 throws Exception { 
 if (!writer.getName().equals("age")) { 
 writer.serializeAsField(pojo, jgen, provider); 
 } 
 } 
 }; 
//設定 FilterProvider 
 FilterProvider filterProvider = new SimpleFilterProvider() 
 .addFilter("myFilter", newFilter); 
 mapper.setFilterProvider(filterProvider).writeValueAsString(person);

自定義序列化和反序列化


當 Jackson 預設序列化和反序列化的類不能滿足實際需要,可以自定義新的序列化和反序列化的類。

  • 自定義序列化類。自定義的序列化類需要直接或間接繼承 StdSerializer 或 JsonSerializer,同時需要利用 JsonGenerator 生成 json,重寫方法 serialize,示例如下:

清單 1

public class CustomSerializer extends StdSerializer<Person> { 
@Override 
public void serialize(Person person, JsonGenerator jgen, 
SerializerProvider provider) throws IOException { 
jgen.writeStartObject(); 
jgen.writeNumberField("age", person.getAge()); 
jgen.writeStringField("name", person.getName()); 
jgen.writeEndObject(); 
} 
}

JsonGenerator 有多種 write 方法以支援生成複雜的型別的 json,比如 writeArray,writeTree 等 。若想單獨建立 JsonGenerator,可以通過 JsonFactory() 的 createGenerator。

  • 自定義反序列化類。自定義的反序列化類需要直接或間接繼承 StdDeserializer 或 StdDeserializer,同時需要利用 JsonParser 讀取 json,重寫方法 deserialize,示例如下:

清單 2 . 自定義反序列化

public class CustomDeserializer extends StdDeserializer<Person> { 
 @Override 
 public Person deserialize(JsonParser jp, DeserializationContext ctxt) 
 throws IOException, JsonProcessingException { 
 JsonNode node = jp.getCodec().readTree(jp); 
 Person person = new Person(); 
 int age = (Integer) ((IntNode) node.get("age")).numberValue(); 
 String name = node.get("name").asText(); 
 person.setAge(age); 
 person.setName(name); 
return person; 
} 
 }

JsonParser 提供很多方法來讀取 json 資訊, 如 isClosed(), nextToken(), getValueAsString()等。若想單獨建立 JsonParser,可以通過 JsonFactory() 的 createParser。

  • 定義好自定義序列化類和自定義反序列化類,若想在程式中呼叫它們,還需要註冊到 ObjectMapper 的 Module,示例如下:

清單 3 . 注 冊 M odule 示例

SimpleModule module = new SimpleModule("myModule"); 
module.addSerializer(new CustomSerializer(Person.class)); 
module.addDeserializer(Person.class, new CustomDeserializer()); 
mapper.registerModule(module); 
也可通過註解方式加在 java 物件的屬性,方法或類上面來呼叫它們, 
@JsonSerialize(using = CustomSerializer.class) 
@JsonDeserialize(using = CustomDeserializer.class) 
public class Person

樹模型處理


Jackson 也提供了樹模型(tree model)來生成和解析 json。若想修改或訪問 json 部分屬性,樹模型是不錯的選擇。樹模型由 JsonNode 節點組成。程式中常常使用 ObjectNode,ObjectNode 繼承於 JsonNode,示例如下:

清單 1 . ObjectNode 生成和解析 json 示例

ObjectMapper mapper = new ObjectMapper(); 
//構建 ObjectNode 
ObjectNode personNode = mapper.createObjectNode(); 
//新增/更改屬性 
personNode.put("name","Tom"); 
personNode.put("age",40); 
ObjectNode addressNode = mapper.createObjectNode(); 
addressNode.put("zip","000000"); 
addressNode.put("street","Road NanJing"); 
//設定子節點 
personNode.set("address",addressNode); 
//通過 path 查詢節點 
JsonNode searchNode = personNode.path("street "); 
//刪除屬性 
((ObjectNode) personNode).remove("address"); 
//讀取 json 
JsonNode rootNode = mapper.readTree(personNode.toString()); 
//JsonNode 轉換成 java 物件 
Person person = mapper.treeToValue(personNode, Person.class); 
//java 物件轉換成 JsonNode 
JsonNode node = mapper.valueToTree(person);

總結

本文首先通過與其他 Java 的 json 的框架比較,介紹了 Jackson 的優點,並且描述了 Jackson 的 核心模組的組成,以及每個部分的作用。然後, 本文通過示例,講解 Jackson 的基本用法,介紹了 ObjectMapper 的 write 和 read 方法,ObjectMapper 的配置資訊設定,以及 jackson-annotations 包下注釋的運用。最後,本文詳細的介紹了 Jackson 的高階用法,這也是本文的重點。這些高階用法包括不同型別的日期格式處理(普通日期的型別,jdk 8 的日期型別,joda 的日期型別),List 和 Map 等泛型的反序列化,屬性的視覺化管理,Jackson 的 三種屬性過濾方式,自定義序列化和反序列化的實現以及樹模型的使用。通過本文的系統地講解,相信讀者對 Jackson 會有更深刻而全面的掌握。

轉 :https://www.cnblogs.com/guanbin-529/p/11489104.html