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

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

本文經過3個問題來討論如何使用 GSON 把JSON反序列化爲List。java

問題1

有這樣兩個類:程序員

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

那下面的測試能經過嗎?json

@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參數獲得這個信息。那麼改爲下面這樣呢?ui

ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", ArrayList<MyObj>.class);
更糟糕,連編譯都沒法經過!由於Java的泛型是用  擦拭法

實現的,說白了只是編譯器提供給程序員的語法糖,根本不存在ArrayList<MyObj>這樣一個類。那麼怎樣才能讓GSON反序列化出咱們想要的泛型對象呢?答案是,請TypeToken幫忙:google

@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 提取到。spa

問題3

若是我想寫一個通用的方法,把json反序列化成List,下面這個方法可行嗎?.net

public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) { Type type = new TypeToken<ArrayList<T>>() {}.getType(); return new Gson().fromJson(json, type); }

這個測試能經過嗎?code

@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類型的對象。

相關文章
相關標籤/搜索