本文鏈接:http://www.jianshu.com/p/0e40a52c0063
JSON (官網(wǎng)) 是一種文本形式的數(shù)據(jù)交換格式,它比xml更輕量、比二進(jìn)制容易閱讀和編寫,調(diào)式也更加方便。其重要性不言而喻。解析和生成的方式很多,java中最常用的類庫有:JSON-Java、Gson、Jackson、FastJson等。
該系列其它文章
你真的會用Gson嗎?Gson使用指南(一)你真的會用Gson嗎?Gson使用指南(二)你真的會用Gson嗎?Gson使用指南(三)你真的會用Gson嗎?Gson使用指南(四)注:此系列基于Gson 2.4。
本次的主要內(nèi)容:
字段過濾的幾種方法基于@Expose注解基于版本基于訪問修飾符基于策略(作者最常用)POJO與JSON的字段映射規(guī)則一、字段過濾的幾種方法
字段過濾Gson中比較常用的技巧,特別是在Android中,在處理業(yè)務(wù)邏輯時可能需要在設(shè)置的POJO中加入一些字段,但顯然在序列化的過程中是不需要的,并且如果序列化還可能帶來一個問題就是 循環(huán)引用 ,那么在用Gson序列化之前為不防止這樣的事件情發(fā)生,你不得不作另外的處理。
以一個商品分類
{ "id": 1, "name": "電腦", "children": [ { "id": 100, "name": "筆記本" }, { "id": 101, "name": "臺式機" } ]}Category為例。一個大分類,可以有很多小分類,那么顯然我們在設(shè)計
public class Category { public int id; public String name; public List<Category> children;}Category類時Category本身既可以是大分類,也可以是小分類。但是為了處理業(yè)務(wù),我們還需要在子分類中保存父分類,最終會變成下面的情況
public class Category { public int id; public String name; public List<Category> children; //因業(yè)務(wù)需要增加,但并不需要序列化 public Category parent; }但是上面的
parent字段是因業(yè)務(wù)需要增加的,那么在序列化是并不需要,所以在序列化時就必須將其排除,那么在Gson中如何排除符合條件的字段呢?下面提供4種方法,大家可根據(jù)需要自行選擇合適的方式。基于@Expose注解
@Expose提供了兩個屬性,且都有默認(rèn)值,開發(fā)者可以根據(jù)需要設(shè)置不同的值。
@Expose
@Expose 注解從名字上就可以看出是暴露的意思,所以該注解是用于對處暴露字段的??墒俏覀円郧坝肎son的時候也沒有@Expose 注解還是不正確的序列化為JSON了么?是的,所以該注解在使用
new Gson()時是不會發(fā)生作用。畢竟最常用的API要最簡單,所以該注解必須和GsonBuilder配合使用。使用方法: 簡單說來就是需要導(dǎo)出的字段上加上@Expose 注解,不導(dǎo)出的字段不加。注意是不導(dǎo)出的不加。
@Expose //@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效@Expose(deserialize = true,serialize = false) //反序列化時生效@Expose(deserialize = false,serialize = true) //序列化時生效@Expose(deserialize = false,serialize = false) // 和不寫一樣注:根據(jù)上面的圖片可以得出,所有值為
true的屬性都是可以不寫的。拿上面的例子來說就是
public class Category { @Expose public int id; @Expose public String name; @Expose public List<Category> children; //不需要序列化,所以不加 @Expose 注解, //等價于 @Expose(deserialize = false,serialize = false) public Category parent; }在使用Gson時也不能只是簡單的
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create();gson.toJson(category);new Gson()了。基于版本
Gson在對基于版本的字段導(dǎo)出提供了兩個注解
@Since和@Until,和GsonBuilder.setVersion(Double)配合使用。@Since和@Until都接收一個Double值。Since和Until注解
使用方法:當(dāng)前版本(GsonBuilder中設(shè)置的版本) 大于等于Since的值時該字段導(dǎo)出,小于Until的值時該該字段導(dǎo)出。
class SinceUntilSample { @Since(4) public String since; @Until(5) public String until;}public void sineUtilTest(double version){ SinceUntilSample sinceUntilSample = new SinceUntilSample(); sinceUntilSample.since = "since"; sinceUntilSample.until = "until"; Gson gson = new GsonBuilder().setVersion(version).create(); System.out.PRintln(gson.toJson(sinceUntilSample));}//當(dāng)version <4時,結(jié)果:{"until":"until"}//當(dāng)version >=4 && version <5時,結(jié)果:{"since":"since","until":"until"}//當(dāng)version >=5時,結(jié)果:{"since":"since"}注:當(dāng)一個字段被同時注解時,需兩者同時滿足條件。
基于訪問修飾符
什么是修飾符?
class ModifierSample { final String finalField = "final"; static String staticField = "static"; public String publicField = "public"; protected String protectedField = "protected"; String defaultField = "default"; private String privateField = "private";}public、static、final、private、protected這些就是,所以這種方式也是比較特殊的。使用方式:使用
ModifierSample modifierSample = new ModifierSample();Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE) .create();System.out.println(gson.toJson(modifierSample));// 結(jié)果:{"publicField":"public","protectedField":"protected","defaultField":"default"}GsonBuilder.excludeFieldsWithModifiers構(gòu)建gson,支持int形的可變參數(shù),值由java.lang.reflect.Modifier提供,下面的程序排除了privateField、finalField和staticField三個字段。到此為止,Gson提供的所有注解就還有一個
@JsonAdapter沒有介紹了,而@JsonAdapter將和TypeAdapter將作為該系列第4篇也是最后一篇文章的主要內(nèi)容。基于策略(自定義規(guī)則)
上面介紹的了3種排除字段的方法,說實話我除了@Expose以外,其它的都是只在Demo用上過,用得最多的就是馬上要介紹的自定義規(guī)則,好處是功能強大、靈活,缺點是相比其它3種方法稍麻煩一點,但也僅僅只是想對其它3種稍麻煩一點而已。
基于策略是利用Gson提供的
ExclusionStrategy接口,同樣需要使用GsonBuilder,相關(guān)API 2個,分別是addSerializationExclusionStrategy和addDeserializationExclusionStrategy分別針對序列化和反序化時。這里以序列化為例。例如:
Gson gson = new GsonBuilder() .addSerializationExclusionStrategy(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { // 這里作判斷,決定要不要排除該字段,return true為排除 if ("finalField".equals(f.getName())) return true; //按字段名排除 Expose expose = f.getAnnotation(Expose.class); if (expose != null && expose.deserialize() == false) return true; //按注解排除 return false; } @Override public boolean shouldSkipClass(Class<?> clazz) { // 直接排除某個類 ,return true為排除 return (clazz == int.class || clazz == Integer.class); } }) .create();有沒有很強大?
二、 POJO與JSON的字段映射規(guī)則
之前在你真的會用Gson嗎?Gson使用指南(二) 屬性重命名時 介紹了
User user = new User("怪盜kidou", 24);user.emailAddress = "ikidou@example.com";@SerializedName這個注解的使用,本節(jié)的內(nèi)容與上一次差不多的,但既然叫映射規(guī)則那么說的自然是有規(guī)律的情況。還是之前User的例子,已經(jīng)去除所有注解:
GsonBuilder提供了FieldNamingStrategy接口和setFieldNamingPolicy和setFieldNamingStrategy兩個方法。默認(rèn)實現(xiàn)
GsonBuilder.setFieldNamingPolicy方法與Gson提供的另一個枚舉類FieldNamingPolicy配合使用,該枚舉類提供了5種實現(xiàn)方式分別為:
FieldNamingPolicy 結(jié)果(僅輸出emailAddress字段) IDENTITY {"emailAddress":"ikidou@example.com"} LOWER_CASE_WITH_DASHES {"email-address":"ikidou@example.com"} LOWER_CASE_WITH_UNDERSCORES {"email_address":"ikidou@example.com"} UPPER_CAMEL_CASE {"EmailAddress":"ikidou@example.com"} UPPER_CAMEL_CASE_WITH_SPACES {"Email Address":"ikidou@example.com"} 自定義實現(xiàn)
GsonBuilder.setFieldNamingStrategy方法需要與Gson提供的FieldNamingStrategy接口配合使用,用于實現(xiàn)將POJO的字段與JSON的字段相對應(yīng)。上面的FieldNamingPolicy實際上也實現(xiàn)了FieldNamingStrategy接口,也就是說FieldNamingPolicy也可以使用setFieldNamingStrategy方法。用法:
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new FieldNamingStrategy() { @Override public String translateName(Field f) { //實現(xiàn)自己的規(guī)則 return null; } }) .create();注意:
@SerializedName注解擁有最高優(yōu)先級,在加有@SerializedName注解的字段上FieldNamingStrategy不生效!本文完
下期預(yù)告(本系列最終篇):
無所不能的TypeAdapter Android/Java開發(fā)
新聞熱點
疑難解答