你真的會用Gson嗎?Gson使用指南(三)

本文為作者根據(jù)日常使用結(jié)合Gson源碼注釋及wiki所作的原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處捂齐。

該系列其它文章

注:此系列基于Gson 2.4布疙。

本次的主要內(nèi)容:

  • 字段過濾的幾種方法
    • 基于@Expose注解
    • 基于版本
    • 基于訪問修飾符
    • 基于策略(作者最常用)
  • POJO與JSON的字段映射規(guī)則

一、字段過濾的幾種方法

字段過濾Gson中比較常用的技巧,特別是在Android中凿滤,在處理業(yè)務邏輯時可能需要在設置的POJO中加入一些字段挚冤,但顯然在序列化的過程中是不需要的况增,并且如果序列化還可能帶來一個問題就是 循環(huán)引用 ,那么在用Gson序列化之前為不防止這樣的事件情發(fā)生训挡,你不得不作另外的處理澳骤。

以一個商品分類Category 為例。

{
  "id": 1,
  "name": "電腦",
  "children": [
    {
      "id": 100,
      "name": "筆記本"
    },
    {
      "id": 101,
      "name": "臺式機"
    }
  ]
}

一個大分類澜薄,可以有很多小分類为肮,那么顯然我們在設計Category類時Category本身既可以是大分類,也可以是小分類肤京。

public class Category {
    public int id;
    public String name;
    public List<Category> children;
}

但是為了處理業(yè)務颊艳,我們還需要在子分類中保存父分類,最終會變成下面的情況

public class Category {
    public int id;
    public String name;
    public List<Category> children;
    //因業(yè)務需要增加,但并不需要序列化
    public Category parent; 
}

但是上面的parent字段是因業(yè)務需要增加的棋枕,那么在序列化是并不需要白修,所以在序列化時就必須將其排除,那么在Gson中如何排除符合條件的字段呢?下面提供4種方法戒悠,大家可根據(jù)需要自行選擇合適的方式熬荆。

基于@Expose注解

@Expose提供了兩個屬性,且都有默認值绸狐,開發(fā)者可以根據(jù)需要設置不同的值卤恳。

@Expose

@Expose 注解從名字上就可以看出是暴露的意思,所以該注解是用于對外暴露字段的寒矿⊥涣眨可是我們以前用Gson的時候也沒有@Expose 注解還不是正確的序列化為JSON了么?是的,所以該注解在使用new Gson() 時是不會發(fā)生作用符相。畢竟最常用的API要最簡單拆融,所以該注解必須和GsonBuilder配合使用。

使用方法: 簡單說來就是需要導出的字段上加上@Expose 注解啊终,不導出的字段不加镜豹。注意是不導出的不加

@Expose //
@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效蓝牲,等價于上一條
@Expose(deserialize = true,serialize = false) //反序列化時生效
@Expose(deserialize = false,serialize = true) //序列化時生效
@Expose(deserialize = false,serialize = false) // 和不寫注解一樣

注:根據(jù)上面的圖片可以得出趟脂,所有值為true的屬性都是可以不寫的(默認值是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時也不能只是簡單的new Gson()了昔期。

Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .create();
gson.toJson(category);
基于版本

Gson在對基于版本的字段導出提供了兩個注解 @Since@Until,和GsonBuilder.setVersion(Double)配合使用。@Since@Until都接收一個Double值佛玄。

Since和Until注解

使用方法:當前版本(GsonBuilder中設置的版本) 大于等于Since的值時該字段導出硼一,小于Until的值時該該字段導出。

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));
}
//當version <4時梦抢,結(jié)果:{"until":"until"}
//當version >=4 && version <5時般贼,結(jié)果:{"since":"since","until":"until"}
//當version >=5時,結(jié)果:{"since":"since"}

注:當一個字段被同時注解時奥吩,需兩者同時滿足條件具伍。

基于訪問修飾符

什么是修飾符? publicstatic 圈驼、finalprivate望几、protected 這些就是绩脆,所以這種方式也是比較特殊的。
使用方式:

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";
}

使用GsonBuilder.excludeFieldsWithModifiers構(gòu)建gson,支持int形的可變參數(shù),值由java.lang.reflect.Modifier提供靴迫,下面的程序排除了privateField 惕味、 finalFieldstaticField 三個字段。

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"}

到此為止玉锌,Gson提供的所有注解就還有一個@JsonAdapter沒有介紹了名挥,而@JsonAdapter將和TypeAdapter將作為該系列第4篇也是最后一篇文章的主要內(nèi)容。

基于策略(自定義規(guī)則)

上面介紹的了3種排除字段的方法主守,說實話我除了@Expose以外禀倔,其它的都是只在Demo用上過,用得最多的就是馬上要介紹的自定義規(guī)則参淫,好處是功能強大救湖、靈活,缺點是相比其它3種方法稍麻煩一點涎才,但也僅僅只是想對其它3種稍麻煩一點而已鞋既。

基于策略是利用Gson提供的ExclusionStrategy接口,同樣需要使用GsonBuilder,相關(guān)API 2個耍铜,分別是addSerializationExclusionStrategyaddDeserializationExclusionStrategy 分別針對序列化和反序化時邑闺。這里以序列化為例。

例如:

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使用指南(二) 屬性重命名時 介紹了@SerializedName這個注解的使用程储,本節(jié)的內(nèi)容與上一次差不多的蹭沛,但既然叫映射規(guī)則那么說的自然是有規(guī)律的情況。
還是之前User的例子章鲤,已經(jīng)去除所有注解:

User user = new User("怪盜kidou", 24);
user.emailAddress = "ikidou@example.com";

GsonBuilder提供了FieldNamingStrategy接口和setFieldNamingPolicysetFieldNamingStrategy 兩個方法摊灭。

默認實現(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的字段相對應帚呼。上面的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不生效!

本文完


下期預告(本系列最終篇):
  • 無所不能的TypeAdapter

我最近剛剛開通了微信公眾號(怪盜kidou)沪哺,歡迎關(guān)注

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沈自,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辜妓,更是在濱河造成了極大的恐慌枯途,老刑警劉巖忌怎,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異酪夷,居然都是意外死亡榴啸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門晚岭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸥印,“玉大人,你說我怎么就攤上這事坦报】馑担” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵燎竖,是天一觀的道長璃弄。 經(jīng)常有香客問我,道長构回,這世上最難降的妖魔是什么夏块? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮纤掸,結(jié)果婚禮上脐供,老公的妹妹穿的比我還像新娘。我一直安慰自己借跪,他們只是感情好政己,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掏愁,像睡著了一般歇由。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上果港,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天沦泌,我揣著相機與錄音,去河邊找鬼辛掠。 笑死谢谦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的萝衩。 我是一名探鬼主播回挽,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猩谊!你這毒婦竟也來了千劈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤牌捷,失蹤者是張志新(化名)和其女友劉穎墙牌,沒想到半個月后袁梗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡憔古,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了淋袖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸿市。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖即碗,靈堂內(nèi)的尸體忽然破棺而出焰情,到底是詐尸還是另有隱情,我是刑警寧澤剥懒,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布内舟,位于F島的核電站,受9級特大地震影響初橘,放射性物質(zhì)發(fā)生泄漏验游。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一保檐、第九天 我趴在偏房一處隱蔽的房頂上張望耕蝉。 院中可真熱鬧,春花似錦夜只、人聲如沸垒在。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽场躯。三九已至,卻和暖如春旅挤,著一層夾襖步出監(jiān)牢的瞬間踢关,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工谦铃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留耘成,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓驹闰,卻偏偏與公主長得像瘪菌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嘹朗,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文為作者根據(jù)日常使用結(jié)合Gson源碼注釋及wiki所作的原創(chuàng)內(nèi)容师妙,轉(zhuǎn)載請注明出處。 該系列其它文章 你真的會用G...
    怪盜kidou閱讀 70,198評論 37 156
  • 本文為作者根據(jù)日常使用結(jié)合Gson源碼注釋及wiki所作的原創(chuàng)內(nèi)容屹培,轉(zhuǎn)載請注明出處默穴。本文鏈接:http://www...
    怪盜kidou閱讀 378,795評論 210 1,105
  • 1.概述2.Gson的目標3.Gson的性能和擴展性4.Gson的使用者5.如何使用Gson 通過Maven來使用...
    人失格閱讀 14,234評論 2 18
  • 本文為作者根據(jù)日常使用結(jié)合Gson源碼注釋及wiki所作的原創(chuàng)內(nèi)容怔檩,轉(zhuǎn)載請注明出處。 該系列其它文章 你真的會用G...
    怪盜kidou閱讀 78,290評論 119 213
  • “我在惠州了蓄诽,準備坐車回深圳薛训。”5點23分的信息仑氛。 而我昨晚打出去的電話是8點多乙埃。 三天假期終于結(jié)束,同事們都來上...
    李北生閱讀 356評論 0 2