1. 程式人生 > >使用Gson解析複雜的泛型巢狀泛型資料結構

使用Gson解析複雜的泛型巢狀泛型資料結構

一、Gson

Gson是由Google自家出來的Json解析庫,使用起來相容性方面當然會有很多優勢,而且解析Json資料也很方便,掌握了Gson的一些基本使用之後就可以使用它解析很多複雜的Json資料了。但當我們要解析一個複雜的資料結構時,比如說List<CardBean<E>>這種,泛型之中還有泛型的陣列結構,就比較麻煩了。下面我會給出一種方案,在此之前我還是先簡單的介紹一下Gson的一些東西,如果懂的大神請直接跳過,直接看第二節。

在使用Gson之前,你需要了解一下 反射 相關的知識和 泛型 相關的知識。

泛型的相關知識請參考我的第一篇:Java泛型(一)——泛型的定義與使用

Gson中的幾個重要物件

JsonParser : 解析器,可以將String型別的Json資料解析成JsonElement元素。

JsonElement: Json的基本物件元素,它的拓展類有:JsonObject、JsonArray、JsonPrimitive。不同的類封裝了不同的方法,以便於更好的呼叫。

JsonObject: Json的物件,類似於Sun裡面的JSONObject,封裝了物件的資訊。

JsonArray: Json的陣列,同樣類似於Sun裡面的JSONArray,封裝了物件陣列資訊(或者子陣列資訊).

JsonPrimitive: Json原始物件,Sun提供的JSON中沒有這個類,這裡它封裝了Java中基本物件。

Gson: Gson物件,用來將程式中定義的物件轉換成String型別的Json格式;同時也可以將String型別的Json格式轉換成我們想要的物件。

TypeToken: 用於提取泛型引數的型別,用於在解析器將Json解析成我們的實際物件時,在提供給反射機制,以便於例項化具體的類別。

Gson解析泛型

使用Gson的時候,我們一般無外乎是將Json格式的字串解析成物件、以及將物件轉化成Json格式以便於傳輸。

它的最基本的兩個方法如下:

toJson(obj,type): 將物件轉化為Json字串

fromJson(obj,type): 將Json字串轉為type對應的物件

上面的使用方法大家都知道,我就不舉例了。

但當我們使用Gson去解析泛型的時候,我目前就遇到兩個問題:

問題
解析出來的泛型物件是一個LinkedTreeMap,這個問題比較普遍,解決方法也比較簡單。是因為使用fromJson的時候沒有給泛型類別新增Type說明,例項下面程式碼附上。

/**
     * 第一種,沒有在將型別的泛型Type傳入,則得到的泛型物件是一個LinkedTreeMap
     */
    public static void test1() {
        CardBean<CardBean1000> cardBean = new CardBean<>();
        cardBean.cardViewType = 1000;
        CardBean1000 cardBean1000 = new CardBean1000();
        cardBean1000.agenda = "男";
        cardBean1000.name = "張三";
        cardBean.data = cardBean1000;
        String jsonStr = gson.toJson(cardBean);
        System.out.println(jsonStr);
        CardBean transCard = gson.fromJson(jsonStr, cardBean.getClass());
        System.out.println(transCard.data.getClass().getName());
    }

    /**
     * 第二種,將含有泛型具體的類別Type資訊傳入,則將能夠轉為具體的類別。
     */
    public static void test2() {
        CardBean<CardBean1000> cardBean = new CardBean<>();
        cardBean.cardViewType = 1000;
        CardBean1000 cardBean1000 = new CardBean1000();
        cardBean1000.agenda = "男";
        cardBean1000.name = "張三";
        cardBean.data = cardBean1000;
        Type type = new TypeToken<CardBean<CardBean1000>>() {
        }.getType();
        String jsonStr = gson.toJson(cardBean);
        System.out.println(jsonStr);
        CardBean transCard = gson.fromJson(jsonStr, type);
        System.out.println(transCard.data.getClass().getName());
        ;
    }

程式結果對比:

test1——將物件轉化成Json格式: {"data":{"name":"張三","agenda":"男"},"cardViewType":1000}
test1——沒有傳入泛型類別: com.google.gson.internal.LinkedTreeMap
test2——傳入泛型類別: main.Test$CardBean1000
將物件轉化成Json格式並沒有什麼大問題,在test1中沒有傳入泛型的Type類別,因此解析器解析的時候沒有辦法確定泛型的型別,框架中預設將KV形式的Json儲存在了LinkedTreeMap中,將其賦值給了泛型 T,我們只要使用TypeToken將泛型資訊給提取出來,那麼解析器解析的時候就可以具體知道類別(Class),便可以用反射來例項化物件了。

二、Gson解析巢狀泛型陣列

當我們伺服器返回的Json陣列中的物件不同時,就會出現解析List<CardBean<E>>這樣的巢狀泛型陣列問題。

解析方案

解析上述型別的時候,我們直接使用fromJson(json,Type),是無法一步到位的,我們只能拿到一個List<CardBean> 的陣列列表,但CardBean<T> 的泛型我們並沒有解析,實際上也無法解析,因為裡面是什麼樣的物件我們是不知道的,我們也無法確定陣列中的某一個位置是什麼樣的型別。同樣類似於上面的問題,Gson會把CardBean 中的 T 解析成一個LinkedTreeMap,第一次解析我們只能拿到這個資訊,我們如何知道里面的json物件是對應的那一個類呢?我們使用資料結構的方法解決這個問題,這裡我們可以在CardBean物件裡增加一個type欄位,該type與具體的類有一個對映關係(可以儲存在HashMap中,也可以使用列舉)。

說到這裡,很多人應該知道我的思路了,就是我自己做一次解析,取得CardBean裡面的type欄位,再通過對映關係找到對應的class,然後通過反射解析該物件。通過這樣的方式我們就可以達到解析複雜巢狀泛型的目的了,這裡是兩層,多層的話可以使用遞迴方式,或者迴圈的方式解決 。

說了那麼多,show me the code! 附上程式碼吧:

public static void cardViewTypeParse() {
        CardBean<CardBean1000> cardBean = new CardBean<>();
        CardBean1000 cardBean1000 = new CardBean1000();
        cardBean1000.agenda = "女";
        cardBean1000.name = "何小蘭";
        cardBean.data = cardBean1000;
        cardBean.cardViewType = 1000;

        CardBean<CardBean1001> cardBean1 = new CardBean<>();
        CardBean1001 cardBean1001 = new CardBean1001();
        cardBean1001.agenda = "男";
        cardBean1001.name = "景曉明";
        Extra extra = new Extra();
        extra.extra = "extra";
        cardBean1001.extra = extra;
        cardBean1.data = cardBean1001;
        cardBean1.cardViewType = 1001;

        JsonArray jArray = new JsonArray();
        JsonObject jObject = new JsonObject();
        // TODO toJson(Object src,Type typeOfSrc)具體用來幹嘛?有沒有感覺都沒什麼區別,大神指導一下
        jArray.add(parser.parse(gson.toJson(cardBean, cardBean.getClass())));
        jArray.add(parser.parse(gson.toJson(cardBean1, cardBean1.getClass())));

        System.out.println(jArray.toString());

        List<CardBean> list0 = gson.fromJson(jArray.toString(), new TypeToken<List<CardBean>>() {
        }.getType());
        for (CardBean cardBean2 : list0) {
            System.out.println(cardBean2.cardViewType);
            CardViewType cardViewType = CardViewType.getCardViewType(cardBean2.cardViewType);

            CardBeanClient cardBeanClient = new CardBeanClient<>();
            cardBeanClient.cardViewType = cardViewType;
            cardBeanClient.data = gson.fromJson(gson.toJson(cardBean2.data), cardViewType.clazz);
            System.out.println(cardBeanClient.data.toString());
            if (cardBean2.data instanceof Map) {
                System.out.println(((Map) cardBean2.data).get("name"));
            }
        }

}


    /**
     * Client端的Bean包裝類
     * @author David
     *
     * @param <T>
     */
    public static class CardBeanClient<T> {
        T data;
        CardViewType cardViewType;
    }
    /**
     * Server端的Bean包裝類
     * @author David
     *
     * @param <T>
     */
    public static class CardBeanServer<T> {
        T data;
        int cardViewType;

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return data.toString() + "    " + cardViewType;
        }
    }

    /**
    * 列舉:type與class的對映關係
    */
    public enum CardViewType {
        CardViewType1000(1000, CardBean1000.class), CardViewType1001(1001, CardBean1001.class);
        int type;
        Class clazz;

        CardViewType(int type, Class clazz) {
            this.type = type;
            this.clazz = clazz;
        }

        // 通過value獲取對應的列舉物件
        public static CardViewType getCardViewType(int value) {
            for (CardViewType cardViewType : CardViewType.values()) {
                if (value == cardViewType.type) {
                    return cardViewType;
                }
            }
            return null;
        }
    }
     /**
     * 具體的Bean資料
     */
    public static class CardBean1000 {
        String name;
        String agenda;

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return name + "    " + agenda;
        }
    }

    public static class CardBean1001 {
        String name;
        String agenda;
        Extra extra;

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return name + "    " + agenda + "    " + extra.extra;
        }
    }

    public static class Extra {
        String extra;
    }

結果列印:

json:[{"data":{"name":"何小蘭","agenda":"女"},"cardViewType":1000},{"data":{"name":"景曉明","agenda":"男","extra":{"extra":"extra"}},"cardViewType":1001}]

1000
type = CardViewType1000   main.Test$CardBean1000
1001
type = CardViewType1001   main.Test$CardBean1001

相關推薦

使用Gson解析複雜資料結構

一、Gson Gson是由Google自家出來的Json解析庫,使用起來相容性方面當然會有很多優勢,而且解析Json資料也很方便,掌握了Gson的一些基本使用之後就可以使用它解析很多複雜的Json資料了。但當我們要解析一個複雜的資料結構時,比如說List<

陣列++應用例項

泛型陣列 使用泛型方法時,也可以傳遞和返回一個泛型陣列。 【接收和返回泛型陣列】 @SuppressWarnings("unchecked") public class GeneriseDemo30 { public static void

Gson和fastJson 解析的json資料

Test /* * { "code": 1, "datas": [{ "address": "深圳",

fastjson解析

/** * author zoush * CreateTime 2017-06-03 16:01 * 直接上虛擬碼 */ public class Outer<T> {

使用swagger-bootstarap-ui 響應類3層顯示的坑

正常一個分頁查詢的介面返回格式應該是 返回   資料統一的封裝類<分頁資料<要展示的資料類>> 得到的也就是一個3層巢狀2層泛型的資料結構! 也就是這樣 其實也就是 PageHelper 提供的 pageInfo 資訊的複製 加上sw

java 詳解(普通、 萬用字元、 介面,陣列,方法,

JDK1.5 令我們期待很久,可是當他釋出的時候卻更換版本號為5.0。這說明Java已經有大幅度的變化。本文將講解JDK5.0支援的新功能-----Java的泛型. 1、Java泛型  其實Java

Java--應用--介面、方法、陣列、

1、泛型介面 1.1泛型介面的基本概念 1.2泛型介面實現的兩種方式 定義子類:在子類的定義上也宣告泛型型別 interface Info<T>{ // 在介面上定義泛型 pub

Java示例

/* * 泛型巢狀例項 * date: 2012-10-22 * author: Alex Hohh */ // 泛型類Info<K,V> class Info<K,V>{

利用Gson解析多層的JSON資料

資料例項: { "error": 0, "status": "success", "results": [ { "currentCity

Gson解析JSON格式資料

來源說明: 最近在無聊,剛剛又想學一下安卓的APP, 剛剛好看到"中國天氣網"那裡面的有免費的API.剛剛好又想到用GSON解析,我學了一下. 1.資料格式 { "user":"

如何重構多重“箭頭”程式碼

本文轉載自 酷 殼 – CoolShell 陳皓。 所謂箭頭型程式碼,基本上來說就是下面這個圖片所示的情況。 那麼,這樣“箭頭型”的程式碼有什麼問題呢?看上去也挺好看的,有對稱美。但是…… 關於箭頭型程式碼的問題有如下幾個: 1)我的顯示器不夠寬,箭頭型程式碼縮排太狠了,需

使用GSON解析複雜資料——天氣資訊

最近在做自己的App時,要在主介面上新增簡單的天氣資訊顯示,然後就理所當然的跑到百度查詢如何才能獲取到天氣資訊,最後決定採用第三方天氣資訊服務商提供的資料,在看第三方提供的API說明時發現,獲取到的天氣資料是Json格式的,需要自己解析。又是經過一番百度,最後確定使用Google

使用Gson解析複雜的json資料

我們app介面資料返回通常是以下格式: {“code”:“0000”,“data”: {“code”:“0002”,“resultData”:null,“resultMsg”:“使用者Token過期,請重新登入”,“error”:[],“msg”:""} 把以上的json資料放線上J

Gson解析複雜Json資料

implementation'com.google.code.gson:gson:2.8.0' 然後根據api獲取到的json資料 { "status": "1", "info": "OK", "infocode": "10000",

手把手教你怎麼解析多層的JSON資料(使用JSONModel)

使用API API介紹 參考的JSON資料(可能與你看到的不同) { "date": "20181020", "stories": [ { "title": "每週一吸 · 狸花貓",

GSON解析複雜的JSON陣列

1.GSON的兩個重要方法   在GSON的API中,提供了兩個重要的方法:toJson()和fromJson()方法。其中,toJson()方法用來實現將Java物件轉換為相應的JSON資料,fromJson()方法則用來實現將JSON資料轉換為相應的Jav

Gson使用及多層 json 定義類

問題描述 對於簡單的Json資料,其對應的java bean 也比較簡單,尤其用GSON處理的時候。 但是如果是多層巢狀的json資料,如果是手工用JSONArray和JSONObject進行解析,還是可以的,雖然會繁瑣一點。但是如果用GSON開源庫解析,有

Gson解析複雜的Json字串

前提:自行將Gson開源庫匯入到工程中(不會的,請自行百度)。 這是本人第一次寫部落格,如有錯誤,請您見諒,也歡迎與我交流! 需要解析的Json字串為: { "error_code": 0, "reason"

Gson Object與json轉換 物件

解決問題  正確: { "data":{accesstoken : "odA5niNeOhhi1cIK0eOGhrxCB7ClG9R4gl%2Fa2%2FNcOaJ42tWayXKZZZBgIPsh1tRLshlxWyXlEyY...", expirein :"2017-11

通過GSON解析複雜json資料(二)

這裡我們依舊用上文中的 json 字串 , 由於轉換為 map 依舊需要 javaBean , 所有我們的實體物件也不發生改變 這裡我們需要活用 java 反射和型別對比實現需求 先看程式碼 package com.jacx.test.test01.