本文经过3个问题来讨论如何使用 GSON 把JSON反序列化为List。java
有这样两个类:程序员
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()); }
答案是,测试 通不过 !缘由是GSON不知道objList的具体类型,所以只能选择默认的ArrayList。更详细的解释,能够参考这篇文章和ConstructorConstructor类的源代码。若是确实想让GSON建立LinkedList实例该怎么办呢?也简单,就是给objList一个更具体的类型:数组
class MyList {
LinkedList<MyObj> objList = new LinkedList<>(); }
下面的测试能经过吗?测试
@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());
}
很明显,不能。由于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
若是我想写一个通用的方法,把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()); }
答案是,方法不可行(虽然能编译经过),测试通不过!仍是由于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类型的对象。