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