Java中泛型集合List<T>反序列化问题及解决方法
2018-03-21 10:37
507 查看
本文通过3个问题来讨论如何使用 GSON 把JSON反序列化为List。
那下面的测试能通过吗?
更糟糕,连编译都无法通过!因为Java的泛型是用 擦拭法
实现的,说白了只是编译器提供给程序员的语法糖,根本不存在ArrayList<MyObj>这样一个类。那么怎样才能让GSON反序列化出我们想要的泛型对象呢?答案是,请TypeToken帮忙:
GSON提供了 TypeToken 这个类来帮助我们捕获(capture)像ArrayList<MyObj>这样的泛型信息。test3()的第一行代码创建了一个 匿名内部类 ,这样,Java编译器就会把泛型信息编译到这个匿名内部类里,然后在运行时就可以被 getType() 方法用 反射API 提取到。
这个测试能通过吗?
分两步,先反序列化出ArrayList<JsonObject>,然后在一个个的把JsonObject转成classOfT类型的对象。
问题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); 3ff0 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类型的对象。
相关文章推荐
- C#中泛型集合List<T>反序列化问题及解决方法
- NO.94 RestTemplate.getForObject将PO中List<T>的泛型变成LinkedHashMap问题的解决
- Java笔记(8)-泛型、链表、LinkedList<E>、Iterator迭代器、Collections类方法、堆栈、HashMap<K,V>、TreeSet<E>、自动装箱和拆箱
- List<Object>集合按照Object的某个字段排序,解决取不到父类字段问题
- C#泛型集合List<T>自带方法之排序
- JAVA List<Map>结果集处理方法集合
- Java List<T>去重方法,引用类型集合去重
- 解决 ”不允许在查询中显式构造实体类型“问题及使用其他方法实现返回 List<Model对象>或者IQueryable<Model对象>对象
- Java泛型集合结构,List<T>,及其子类ArrayList<T>,LinkedList<T>的使用
- AsParallel \AsQueryable<T>().ToList() [System.ArgumentOutOfRangeException was unhandled" 索引超出范围。必须为非负值并小于集合大小]解决方法
- JAVA List<Map>结果集处理方法集合
- Winform中DataGridView绑定List<T>数据源时,点击DataGridView列头不能自动排序解决方法
- List<> 转换为Dataset的C#代码实现 解决Nullable问题
- .NET中string[]数组和List<string>泛型的相互转换以及Array类的Sort()方法 【整理】
- 将DataTable转换成List<T>泛型集合助手类
- C#读取数据库返回泛型集合 把DataSet类型转换为List<T>泛型集合
- asp.net中,在客户端,加入<%=....%>代码时出现的问题解决方法
- Java中使用hql,sql查询返回的list<Object> 转成需要的实体对象--方法讲解!
- [问题与解决] java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
- C#读取数据库返回泛型集合 把DataSet类型转换为List<T>泛型集合