Java泛型(二)——使用Gson解析复杂的泛型嵌套泛型数据结构
来源:互联网 发布:杠杆炒股盈利算法 编辑:程序博客网 时间:2024/06/06 04:33
- 一Gson
- Gson中的几个重要对象
- Gson解析泛型
- 二Gson解析嵌套泛型数组
- 解析方案
- 疑惑点希望大神能够帮助解决一下
Java泛型(一)——泛型的定义与使用
Java泛型(二)——使用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.LinkedTreeMaptest2——传入泛型类别: 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}]1000type = CardViewType1000 main.Test$CardBean10001001type = CardViewType1001 main.Test$CardBean1001
同时也希望各位大神能够给出一个动态解析嵌套泛型数组的稳定、可靠、高效的框架,小弟不胜感激!最近做一个项目中需要用到这些知识,希望大神给一些建议。
疑惑点(希望大神能够帮助解决一下):
toJson(Object src,Type typeOfSrc) 具体用来干嘛?使用toJson(Object str)同样会调用它,那么这里如果我直接使用toJson(Object src,Type typeOfSrc)能够达到什么其他的效果吗?
没有仔细研究源码,从使用的角度上来看觉得封装仅仅是为了方便。因为我解析的时候调用的是fromJson(String jsonStr,Type typeOfSrc);这里已经指定了type,那么上面的toJson(Object src,Type typeOfSrc)又是干嘛的?系统库要做这一层封装干嘛?有什么其他的用途吗?
- Java泛型(二)——使用Gson解析复杂的泛型嵌套泛型数据结构
- 使用Gson解析复杂的泛型嵌套泛型数据结构
- Gson使用泛型解析
- 使用GSON解析复杂的JSON数据(有DEMO)
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用GSON解析一个复杂的json
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- 使用Gson解析复杂的json数据
- Http Download
- Android比较数据大小
- --ANDROID开发准备--
- Mac上搭建nginx+rtmp直播服务器
- c# 银行管理
- Java泛型(二)——使用Gson解析复杂的泛型嵌套泛型数据结构
- 斯坦福大学卷积神经网络----Module 1 Lesson 1 图像分类
- Advice to professor Xin
- 如果有人问你 SQL 注入的资料,请叫他看这份速查表
- 关于在g++编译C++过程中调用移动构造函数
- nodejs的第二个小程序
- 图像是怎么转换为JPEG图像的
- 传统产业、传统企业为什么要进行互联网转型?
- HDU3450-Counting Sequences