gson处理泛型的问题
来源:互联网 发布:最全生活网络理财投资 编辑:程序博客网 时间:2024/05/16 12:19
工程里之前解析网络请求和做数据缓存都是用的JSONObject,手动解析数据自由度比较高。最近终于受不了一个数据要手动写半天解析过程了,决定换成用自动解析库。
现在使用的比较多的一个是谷歌的gson,一个是阿里的fast-json。网上的资料是说fast-json效率比gson高,但这个库有一些比较隐藏的坑。反正json解析慢点儿对我没什么影响,权衡之下还是打算改用gson。
gson的使用比较简单,
public class Result { @Expose private int code; @Expose private String message; @Expose private String data; private String extra;}网上找的资料一般说是要写pojo类,给各个变量加上set、get方法,但经过实际测试并不需要,具体实现没细看。
处理不想解析的变量有两种方式: 1. 给要解析的变量加上@Expose注解,然后创建gson时调用GsonBuilder.register.exludeFiledsWithoutExposeAnnotation。2.不解析的变量用transient修饰。
遇到两个难题:
一个是gson解析泛型的问题,比如工程里的请求返回结果都是Result结构的,code和message类型固定,但承载了实际返回内容的data都是完全不同类型的。由于java的类型擦除问题,我们解析String和ArrayList<String>类型的data可能要这么做
public Result<String> parseStringResult(Gson gson, Reader reader) { return gson.fromJson(reader, new TypeToken<Result<String>>(){}.getType()); } public Result<ArrayList<String>> parseArrayStringResult(Gson gson, Reader reader) { return gson.fromJson(reader, new TypeToken<Result<ArrayList<String>>>(){}.getType()); }但如果要data成为一个泛型,Result定义为:
public class Result<DATA_TYPE> { @Expose private int code; @Expose private String message; @Expose private DATA_TYPE data;}如果也想用泛型的方式解析Result,用这样的代码是不行的:
private <DATA_TYPE> Result<DATA_TYPE> parseResult(Gson gson, Reader reader) { return gson.fromJson(reader, new TypeToken<Result<DATA_TYPE>>(){}.getType()); }
DATA_TYPE作为这个函数的泛型,会被直接擦除。可以这么做:
private <DATA_TYPE> Result<DATA_TYPE> parseResult(Gson gson, Reader reader, final Type typeOfData) { Type resultType = new ParameterizedType() { @Override public Type[] getActualTypeArguments() { return new Type[]{typeOfData}; } @Override public Type getOwnerType() { return null; } @Override public Type getRawType() { return Result.class; } }; return gson.fromJson(reader, resultType); }
DATA_TYPE的类型直接通过Type类型参数传入,使得最终传递给gson的type包含了所有泛型信息。
之前遇到类型擦除的问题主要还是在于对java的泛型实现不了解,认识到Class和Type的区别之后就明白了。
还有一个棘手的问题就是有的类不好自动解析,比如这种:
{ "list":[ { "type":"text", "text":"this is text" }, { "type":"image", "image":{ "image_url":"http://……", "width":600, "height":400 } }, { "type":"video", "video":{ "thumb_url":"http://……", "play_url":"http://……", "duration":40000 } } ]}
list的子元素可能有不同类型,通过type进行区分,这时list的子元素是要手动解析的,自己实现的解决方案如下:
先定义一个接口IFuzzyDeserializeBean,需要手动解析的数据实现这个接口
public interface IFuzzyDeserializeBean { public void deserialize(JsonElement element, JsonDeserializationContext deserializationContext) throws JsonParseException;}再定义IFuzzyDeserializeBean接口的解析类,
public class FuzzyBeanDeserializer implements JsonDeserializer<IFuzzyDeserializeBean> { @Override public IFuzzyDeserializeBean deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { Class c = TypeToken.get(type).getRawType(); try { IFuzzyDeserializeBean bean = (IFuzzyDeserializeBean) c.newInstance(); bean.deserialize(jsonElement, jsonDeserializationContext); return bean; } catch (Exception e) { e.printStackTrace(); return null; } }}将IFuzzyDeserializeBean的解析类注册到gson
public class GsonInstance { private static ThreadLocal<Gson> gson = new ThreadLocal<Gson>() { @Override protected Gson initialValue() { return new GsonBuilder().registerTypeHierarchyAdapter(IFuzzyTransBean.class, new FuzzyBeanTranser()). registerTypeHierarchyAdapter(FuzzyBeanDeserializer.class, new FuzzyBeanDeserializer()). excludeFieldsWithoutExposeAnnotation().create(); } }; public static Gson get() { return gson.get(); }}
定义需要手动解析的数据,先取出type进行判断,然后再通过JsonDesrializationContext完成具体的Image或Video或Text的解析。
public class ListItem implements IFuzzyDeserializeBean{ private String type; private String text; private Image image; private Video video; @Override public void deserialize(JsonElement element, JsonDeserializationContext deserializationContext) throws JsonParseException { if (!element.isJsonObject()) { return; } JsonObject obj = element.getAsJsonObject(); JsonElement typeElement = obj.get("type"); if (null == typeElement || !typeElement.isJsonPrimitive()) { return; } type = typeElement.getAsString(); JsonElement content; switch (type) { case "text": content = obj.get("text"); if (null != content && content.isJsonPrimitive()) { text = content.getAsString(); } break; case "image": content = obj.get("text"); if (null != content && content.isJsonObject()) { image = deserializationContext.deserialize(content, Image.class); } break; case "video": content = obj.get("video"); if (null != content && content.isJsonObject()) { video = deserializationContext.deserialize(content, Video.class); } break; default: break; } } public static class Video { @Expose private String thumb_url; @Expose private String play_url; @Expose private long duration; } public static class Image { @Expose private String image_url; @Expose private int width; @Expose private int height; }}
public class ListData { @Expose private ArrayList<ListItem> list;}
0 0
- gson处理泛型的问题
- GSON处理时间的问题
- Gson处理mongoDB的ObjectId的问题
- 解决Gson 处理Map将整型处理为浮点型的问题
- Android开发:用Gson处理泛型的方法
- Gson解析时对于不确定泛型的处理
- Gson解析json对不确定泛型的处理
- Gson出现的问题
- GSON TypeToken 解决泛型问题
- Gson是如何在运行时处理字段的泛型信息
- 关于Gson解析关键字处理问题
- 使用Gson处理解析泛型类型对象
- gson 处理
- Gson使用遇到的问题
- gson的一些相关问题
- Gson的混淆打包问题
- Gson使用中遇到的Date格式问题。日期格式处理
- Gson使用中遇到的Date格式问题。日期格式处理
- Ubuntu 服务配置(sysv-rc-conf)
- spring IOC容器
- 每日总结-1
- 缺陷:域与静态方法
- 常用的iOS第三方资源
- gson处理泛型的问题
- 使用MediaPlayer的简单音乐播放器功能
- JSP中的九大内置对象
- js函数中this是全局变量还是当前对象
- 2540--第二天--特征值的添加和读写
- NoSQL
- Cocos2d-x 学习日记(一)
- iOS中KVO模式的解析与应用
- 理性选择SQL和NoSQL解决方案