GSON使用筆記(3) -- 如何還原序列化出List

來源:互聯網
上載者:User

標籤:java   gson   json   

本文通過3個問題來討論如何使用GSON把JSON還原序列化為List。

問題1

有這樣兩個類:

class MyObj {    int x;}class MyList {    List<MyObj> objList = new LinkedList<>();}
那下面的測試能通過嗎?

    @Test    public void test1() {        MyList myList = new Gson().fromJson("{objList:[]}", MyList.class);        Assert.assertEquals(LinkedList.class, myList.objList.getClass());    }

答案1

答案是,測試通不過!原因是GSON不知道objList的具體類型,因此只能選擇預設的ArrayList。更詳細的解釋,可以參考這篇文章和ConstructorConstructor類的原始碼。如果確實想讓GSON建立LinkedList執行個體該怎麼辦呢?也簡單,就是給objList一個更具體的類型:

class MyList {    LinkedList<MyObj> objList = new LinkedList<>();}

問題2

下面的測試能通過嗎?

    @Test    public void test2() {        ArrayList<?> list = new Gson().fromJson("[{x:1}]", ArrayList.class);        Assert.assertEquals(1, list.size());        Assert.assertEquals(MyObj.class, list.get(0).getClass());    }

答案2

很明顯,不能。因為fromJson方法不能從"[{x:1}]"參數推測出數組裡放的是MyObj類型的對象,也無法從ArrayList.class參數得到這個資訊。那麼改成下面這樣呢?

ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", ArrayList<MyObj>.class);
更糟糕,連編譯都無法通過!因為Java的泛型是用 擦拭法實現的,說白了只是編譯器提供給程式員的文法糖,根本不存在ArrayList<MyObj>這樣一個類。那麼怎樣才能讓GSON還原序列化出我們想要的泛型對象呢?答案是,請TypeToken幫忙:

    @Test    public void test3() {        Type type = new TypeToken<ArrayList<MyObj>>() {}.getType();        ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", type);        Assert.assertEquals(1, list.size());        Assert.assertEquals(MyObj.class, list.get(0).getClass());    }
GSON提供了 TypeToken這個類來協助我們捕獲(capture)像ArrayList<MyObj>這樣的泛型資訊。test3()的第一行代碼建立了一個 匿名內部類,這樣,Java編譯器就會把泛型資訊編譯到這個匿名內部類裡,然後在運行時就可以被 getType()方法用 反射API提取到。

問題3

如果我想寫一個通用的方法,把json還原序列化成List,下面這個方法可行嗎?

    public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {        Type type = new TypeToken<ArrayList<T>>() {}.getType();        return new Gson().fromJson(json, type);    }
這個測試能通過嗎?

    @Test    public void test4() {        ArrayList<MyObj> list = jsonToList("[{x:1}]", MyObj.class);        Assert.assertEquals(1, list.size());        Assert.assertEquals(MyObj.class, list.get(0).getClass());    }

答案3

答案是,方法不可行(雖然能編譯通過),測試通不過!還是因為Java泛型的擦除法,詳細的回答可以看stackoverflow上的這個問題。那還有辦法實現jsonToList()這個通用方法呢?有的,只是稍微複雜一點:

    public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {        Type type = new TypeToken<ArrayList<JsonObject>>(){}.getType();        ArrayList<JsonObject> jsonObjs = new Gson().fromJson(json, type);                ArrayList<T> listOfT = new ArrayList<>();        for (JsonObject jsonObj : jsonObjs) {            listOfT.add(new Gson().fromJson(jsonObj, classOfT));        }                return listOfT;    }
分兩步,先還原序列化出ArrayList<JsonObject>,然後在一個個的把JsonObject轉成classOfT類型的對象。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.