1. 程式人生 > >使用Gson解析泛型型別

使用Gson解析泛型型別

在程式中訪問網路的時候返回的Json有時候是固定的形式,我們所需要的json資訊是以巢狀的形式給出的,比如
User info:

{
    "result_code":"4000",
    "result_msg":"接受資料正常",
    "json_msg":{
        "user_name":"jack",
        "user_age":15
    }
}

Book info:

{
    "result_code":"4000",
    "result_msg":"接受資料正常",
    "json_msg":{
        "book_name":"Java程式設計思想"
, "book_price":"108.00" }
}

如果我們直接用Gson解析的話,要有對應的實體類才行,比如要解析上面的兩個Json的話,就要有兩個類

public class UsreInfoBean {
    public String result_code;
    public String result_msg;
    public UserInfo json_msg;
}

public class BookInfoBean {
    public String result_code;
    public String result_msg;
    public
BookInfo json_msg; }

另外還需要UserInfo和BookInfo兩個類:

public class UserInfo {
    public String user_name;
    public int user_age;
}

public class BookInfo{
    public String book_name;
    public String book_price;
}

這樣的話每個Json都要對應兩個類,很繁瑣,另外如果Json比較多的話,會產生很多類,而這些類有一半都是多餘的,維護起來也很麻煩。
觀察UserInfoBean和BookInfoBean兩個類,可以發現這兩個類中的成員變數除了json_msg欄位的型別不一樣,其他的都完全一樣,如果能把這連個類統一成一個類的話就能解決類多餘的問題。Java的泛型恰好可以解決這個問題。上面的連個類用泛型可以寫為:

public class InfoBean<T> {
    public String result_code;
    public String result_msg;
    public T json_msg;
}

此時,UserInfoBean和BookInfoBean兩個類就可以寫成InfoBean和InfoBean,不管有多上類都可以寫成這種形式。
試著我們常用的Gson用法去去解析json,

String json = ...; //對應上面的User info的json
//下面程式碼在android studio中會報錯
InfoBean<UserInfo> userInfo = new Gson().fromJson(json, InfoBean<UserInfo>.class);

上面的程式碼並不能執行,原因是InfoBean是泛型,並不能直接獲取class型別。通過android studio的程式碼提示功能可以看到Gson的fromJson()方法解析String型別的json有兩種:

Object fromJson(Sting, Class<Object>)
Object fromJson(String, Type)

第一個方法就是我們一般常用的,接受class型別, 第二個方法接受一個Type型別,Type型別一般與與泛型的型別推斷有關,查閱這個方法的文件可以發現這個方法就是用來處理泛型型別的,文件中介紹需要用TypeToken來獲取泛型的type型別,並且給出了具體的用法:

Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();

按照上面的形式現在我們來處理InfoBean:

String json = ...; //對應上面的User info的json
Type type = new TypeToken<InfoBean<UserInfo>>(){}.getType();
InfoBean<UserInfo> userInfo = new Gson.fromJson(json, type);

現在就可以正確的獲取userInfo物件了。

另外,一般情況下,在json對應的實體類中,類的成員變數的名字要和json對應欄位的名字一樣才能正確解析,比如上面的User info的json中的”result_code”欄位在InfoBean類中要有result_code成員變數來對應。而我們在開發安卓程式的時候一般習慣用駝峰命名法,即result_code欄位一般習慣用resultCode來命名。

Gson對這種情況也是有處理的,只要使用一個註解就可以解決問題:
@SerializedName("result_code")

註解中的名字對應json中的欄位名字,這時我們就可以對實體類中的成員變數隨便命名了。對InfoBean加上註解後:

public class InfoBean<T> {
    @SerializedName("result_code")
    public String resultCode;

    @SerializedName("result_msg")
    public String resultMsg;

    @SerializedName("json_msg")
    public T resultObj;
}

這樣我們在程式碼中訪問json實體類的時候,程式碼的閱讀性就會提高很多。