1. 程式人生 > >你真的會用Gson嗎?Gson使用指南(三)

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

該系列其它文章

注:此係列基於Gson 2.4。

本次的主要內容:

  • 欄位過濾的幾種方法
    • 基於@Expose註解
    • 基於版本
    • 基於訪問修飾符
    • 基於策略(作者最常用)
  • POJO與JSON的欄位對映規則

一、欄位過濾的幾種方法

欄位過濾Gson中比較常用的技巧,特別是在Android中,在處理業務邏輯時可能需要在設定的POJO中加入一些欄位,但顯然在序列化的過程中是不需要的,並且如果序列化還可能帶來一個問題就是 迴圈引用 ,那麼在用Gson序列化之前為不防止這樣的事件情發生,你不得不作另外的處理。

以一個商品分類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;
}

但是為了處理業務,我們還需要在子分類中儲存父分類,最終會變成下面的情況

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

但是上面的parent欄位是因業務需要增加的,那麼在序列化是並不需要,所以在序列化時就必須將其排除,那麼在Gson中如何排除符合條件的欄位呢?下面提供4種方法,大家可根據需要自行選擇合適的方式。

1.1 基於@Expose註解

@Expose提供了兩個屬性,且都有預設值,開發者可以根據需要設定不同的值。
這裡寫圖片描述

@Expose 註解從名字上就可以看出是暴露的意思,所以該註解是用於對外暴露欄位的。可是我們以前用Gson的時候也沒有@Expose 註解還不是照樣正確的序列化為JSON了麼?是的,所以該註解在使用new Gson() 時是不會發生作用。畢竟最常用的API要最簡單,所以該註解必須和GsonBuilder配合使用。

使用方法: 簡單說來就是需要匯出的欄位上加上@Expose 註解,不匯出的欄位不加。注意是不匯出的不加。

@Expose //
@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效
@Expose(deserialize = true,serialize = false) //反序列化時生效
@Expose(deserialize = false,serialize = true) //序列化時生效
@Expose(deserialize = false,serialize = false) // 和不寫一樣

注:根據上面的圖片可以得出,所有值為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);

1.2 基於版本

Gson在對基於版本的欄位匯出提供了兩個註解 @Since 和 @Until,和GsonBuilder.setVersion(Double)配合使用。@Since 和 @Until都接收一個Double值。
這裡寫圖片描述

使用方法:當前版本(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時,結果:{"until":"until"}
//當version >=4 && version <5時,結果:{"since":"since","until":"until"}
//當version >=5時,結果:{"since":"since"}

注:當一個欄位被同時註解時,需兩者同時滿足條件。

1.3 基於訪問修飾符

什麼是修飾符? public、static 、final、private、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構建gson,支援int形的可變引數,值由java.lang.reflect.Modifier提供,下面的程式排除了privateField 、 finalField 和staticField 三個欄位。

ModifierSample modifierSample = new ModifierSample();
Gson gson = new GsonBuilder()
        .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
        .create();
System.out.println(gson.toJson(modifierSample));

// 結果:{"publicField":"public","protectedField":"protected","defaultField":"default"}

到此為止,Gson提供的所有註解就還有一個@JsonAdapter沒有介紹了,而@JsonAdapter將和TypeAdapter將作為該系列第4篇也是最後一篇文章的主要內容。

1.4 基於策略(自定義規則)

上面介紹的了3種排除欄位的方法,說實話我除了@Expose以外,其它的都是隻在Demo用上過,用得最多的就是馬上要介紹的自定義規則,好處是功能強大、靈活,缺點是相比其它3種方法稍麻煩一點,但也僅僅只是想對其它3種稍麻煩一點而已。

基於策略是利用Gson提供的ExclusionStrategy介面,同樣需要使用GsonBuilder,相關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的欄位對映規則

之前在你真的會用Gson嗎?Gson使用指南(二) 屬性重新命名時 介紹了@SerializedName這個註解的使用,本節的內容與上一次差不多的,但既然叫對映規則那麼說的自然是有規律的情況。
還是之前User的例子,已經去除所有註解:

User user = new User("怪盜kidou", 24);
user.emailAddress = "[email protected]";

GsonBuilder提供了FieldNamingStrategy介面和setFieldNamingPolicy和setFieldNamingStrategy 兩個方法。

2.1 預設實現

GsonBuilder.setFieldNamingPolicy 方法與Gson提供的另一個列舉類FieldNamingPolicy配合使用,該列舉類提供了5種實現方式分別為:

FieldNamingPolicy 結果(僅輸出emailAddress欄位)
IDENTITY {“emailAddress”:”[email protected]”}
LOWER_CASE_WITH_DASHES {“email-address”:”[email protected]”}
LOWER_CASE_WITH_UNDERSCORES {“email_address”:”[email protected]”}
UPPER_CAMEL_CASE {“EmailAddress”:”[email protected]”}
UPPER_CAMEL_CASE_WITH_SPACES {“Email Address”:”[email protected]”}

2.2 自定義實現

GsonBuilder.setFieldNamingStrategy 方法需要與Gson提供的FieldNamingStrategy介面配合使用,用於實現將POJO的欄位與JSON的欄位相對應。上面的FieldNamingPolicy實際上也實現了FieldNamingStrategy介面,也就是說FieldNamingPolicy也可以使用setFieldNamingStrategy方法。

用法:

Gson gson = new GsonBuilder()
        .setFieldNamingStrategy(new FieldNamingStrategy() {
            @Override
            public String translateName(Field f) {
                //實現自己的規則
                return null;
            }
        })
        .create();

注意: @SerializedName註解擁有最高優先順序,在加有@SerializedName註解的欄位上FieldNamingStrategy不生效!

相關推薦

真的Gson?Gson使用指南

該系列其它文章 注:此係列基於Gson 2.4。 本次的主要內容: 欄位過濾的幾種方法 基於@Expose註解 基於版本 基於訪問修飾符 基於策略(作者最常用) POJO與JSON的欄位對映規則 一、欄位過濾的幾種方法 欄位過濾Gson中

NSTimer真的!!!

// // SvTestObject.m // SvTimerSample // // Created by maple on 12/19/12. // Copyright (c) 2012 maple. All rights reserved. // #import "SvTestObject.

[NSTimer]NSTimer真的

- (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application wa

NSTimer真的??

- (void)applicationDidBecomeActive:(UIApplication *)application { [NSThread detachNewThreadSelector:@selector(testTimerSheduleToRunloop1) toTarget:se

UpdatePanel控制元件,真的

文/gxlxzys  出處/部落格園    剛接觸這控制元件的時候,感覺這東西好神奇,把頁面中的東西放進去就能實現非同步重新整理,其它的什麼都不用做。我就這樣一直用了一段時間,最近才發現 UpdatePanel控制元件並不是個簡單的東東,我想肯定還有像我這樣把UpdatePa

Android開發者:真的AsyncTask

【導讀】在Android應用開發的過程中,我們需要時刻注意保證應用程式的穩定和UI操作響應及時,因為不穩定或響應緩慢的應用將給應用帶來不好的印象,嚴重的使用者解除安裝你的APP,這樣你的努力就沒有體現的價值了。本文試圖從AsnycTask的作用說起,進一步的講解一下內部的

真的OneNote

1.前言   使用OneNote做筆記已經有一年多的時間了,從最開始的抵觸,到現在的習慣,心態的轉變主要是由於軟體的周到的使用者體驗。它究竟有什麼特別的地方?有word已經足夠了,為什麼還要

真的StringBuffer

最近在看《How Tomcat Works》這本書,其中有這樣一句程式碼: public void parse() { // Read a set of characters from the socket StringBuffer request =

平時工作中一定到的Linux指令

一、find指令——查詢指令最常用引數:【-name】   根據名稱查詢【-iname】  根據名稱查詢,且忽略大小寫差異最常用命令:【find 目錄名 -name 檔案或目錄名】     根據檔名在指

“問題其實就是的期望和的體驗之間的差別”《Are Your Lights》--- 的燈亮著?讀後感1

        剛剛把《Are Your Lights》看完一遍。有點倉促,於是很多地方,不是特別明白,尤其是有些用綠色標註的話不明白強調的真正含義。          雖說,這是本寫給計算機程式設計師的書,但是我覺得不僅僅在程式設計中有用,在生活中,我們遇到問題的時候都會有

Java多線程編程模式實戰指南:Two-phase Termination模式

增加 row throws mgr 額外 finally join table 還需 停止線程是一個目標簡單而實現卻不那麽簡單的任務。首先,Java沒有提供直接的API用於停止線程。此外,停止線程時還有一些額外的細節需要考慮,如待停止的線程處於阻塞(等待鎖)或者等待狀態(等

Redis 小白指南- 事務、過期、消息通知、管道和優化內存空間

如何 入門 系列 code 場景 消息 運算 封裝 c# Redis 小白指南(三)- 事務、過期、消息通知、管道和優化內存空間 簡介   《Redis 小白指南(一)- 簡介、安裝、GUI 和 C# 驅動介紹》 講的是 Redis 的介紹,以及如何在 Windows

C語言攻略指南流程控制篇

... cpp 流程控制 printf 循環結構 多重 -a 1-43 continue 流程控制語句,或者說控制流語句,是用於控制程序計算操作執行的次序,使我們能實現判斷,選擇,循環等操作。本篇將逐一描述 C語言中的流程控制語句。 選擇結構 if 語句 if(表達式

JNI/NDK開發指南——JNI數據類型及與Java數據類型的映射關系

ons 轉換 類型 art return http 異常 array src 轉載請註明出處:http://blog.csdn.net/xyang81/article/details/42047899 當我們在調用一個

Ubuntu下的戶和權限

新建 特定 要去 ash ubunt 管理員 天數 password 命令 七、增刪群組相關的命令 相同的我們要先介紹兩個重要的設定檔:/etc/group和/etc/gshadow,前面那個事實上和/etc/passwd一樣。而後者就是群組的pa

Android Gradle Plugin指南——依賴關系、android庫和多項目配置

tool 全部 ocs 共享 項目路徑 多項目配置 path 用戶 so文件 原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Dependencies-Android-L

JavaScript中的this—不知道的JavaScript上卷讀書筆記

情況下 修改 位置 必須 細節 fin 有關 zed 重要 this是什麽? this 是在運行時進行綁定的,並不是在編寫時綁定,它的上下文取決於函數調用時的各種條件。this 的綁定和函數聲明的位置沒有任何關系,只取決於函數的調用方式。當一個函數被調用時,會創建一個活動記

Java 調PHP的Web Service

ron eight pad rgs asc ali auto mat 請求 usoap是PHP環境中的開源soap工具,算是用得比較多的一個工具了。 在utf-8環境中,nusoap可以工作得很好。但是當用於中文環境中時,nusoap經常會出現一些讓人不得其解的問題

Qt與FFmpeg聯合開發指南——編碼1:代碼流程演示

開啟 fault 原因 上下 sizeof ffmpeg 不同步 目前 直接 前兩講演示了基本的解碼流程和簡單功能封裝,今天我們開始學習編碼。編碼就是封裝音視頻流的過程,在整個編碼教程中,我會首先在一個函數中演示完成的編碼流程,再解釋其中存在的問題。下一講我們會將編碼功能進

小橙書閱讀指南——插入排序

stat 指定 improve @override n) alt img 解釋 style 算法描述:通常人們在整理撲克的方法是一張一張的來,將每一張牌插入到其他已經有序的牌中的適當位置。在算法的實現中,為了給要插入的元素騰出1個空間,我們需要將其余所有元素在插入之前都向右