搞定 Gson 泛型封装 您所在的位置:网站首页 parameterizedtypeimple 搞定 Gson 泛型封装

搞定 Gson 泛型封装

#搞定 Gson 泛型封装| 来源: 网络整理| 查看: 265

约定一、为何封装,如何封装1.1 为何封装1.2 如何封装二、为何失败?三、如何解决?3.1 实现一个简易的 ParameterizedType3.2 生成 Gson 需要的泛型3.2.1 解析 data 是 Object 的情况3.2.2 解析 data 是 Array 的情况

在你真的会用Gson吗?Gson使用指南(一)的第三节我介绍了在 Gson 中如何使用泛型来简化我们的类设计,但随之而来引入了一个新的问题:封装。不知道各位有没有想过这样一个问题:每次都要用 new TypeToken() {}; 好麻烦,有没有更好的办法?

有更好的办法么?当然有!相信也有不少人自己作了尝试,只是有人欢喜有人愁了,不过没关系,今天我们就来解决这个问题。

约定

本文涉及到的 JSON 格式,如下所示:

// data 为 object 的情况{"code":"0","message":"success","data":{}}// data 为 array 的情况{"code":"0","message":"success","data":[]}

假定第一种对应的 Java 类型为 Result,第二种为 Result

一、为何封装,如何封装

1.1 为何封装 写 new TypeToken() {} 麻烦,IDE 格式化后还不好看不同的地方每进行一次 new TypeToken() {} 操作都会生成一个新的类对于任意类 XXX 都只有两种情况 new TypeToken() {} 和 new TypeToken() {}方便统一管理 1.2 如何封装从上面的我们可以知道,最简单的方法就是提供两个方法分别对应 data 为 Array 和 Object 的情况并接收一个参数,即告知 XXX 的类型,自动将完成 new TypeToken() {} 与 new TypeToken() {} 的过程。

方法原型:

// 处理 data 为 object 的情况public static Result fromJsonObject(Reader reader, Class clazz) {}// 处理 data 为 array 的情况public static Result fromJsonArray(Reader reader, Class clazz){}

二、为何失败?

对于那些尝试着封装过的人可能都这么写过:

public static Result fromJsonArray(Reader reader) { Type type = new TypeToken(){}.getType(); return GSON.fromJson(reader, type);}

当然上面的写法肯定是没有办法完成的,虽然代码不会报错,但运行结果肯定是不对的,因为这里的 T 其实是一个 TypeVariable,他在运行时并不会变成我们想要的 XXX,所以通过 TypeToken 得到的泛型信息只是 "Result"。

三、如何解决?

既然 TypeToken 的作用是用于获取泛型的类,返回的类型为 Type,真正的泛型信息就是放在这个 Type 里面,既然用 TypeToken 生成会有问题,那我们自己生成 Type 就行了嘛。

Type 是 Java 中所有类型的父接口,在 JDK1.8 以前是一个空接口,自 JDK1.8 起多了个 getTypeName() 方法,下面有 ParameterizedType、 GenericArrayType、 WildcardType、 TypeVariable 几个接口,以及 Class 类。这几个接口在本次封装过程中只会用到 ParameterizedType,所以简单说一下:

ParameterizedType 简单说来就是形如“类型”的类型,如:Map。

下面就以 Map 为例讲一下里面各个方法的作用。

public interface ParameterizedType extends Type { // 返回 Map 里的 String 和 User,所以这里返回 [String.class,User.clas] Type[] getActualTypeArguments(); // Map 里的 Map,所以返回值是 Map.class Type getRawType(); // 用于这个泛型上中包含了内部类的情况,一般返回 null Type getOwnerType(); }

所以,知道了这里需要的泛型是怎么回事,一切都好说了,下面我们来完成之前留下的空方法。

3.1 实现一个简易的 ParameterizedTypepublic class ParameterizedTypeImpl implements ParameterizedType { private final Class raw; private final Type[] args; public ParameterizedTypeImpl(Class raw, Type[] args) { this.raw = raw; this.args = args != null ? args : new Type[0]; } @Override public Type[] getActualTypeArguments() { return args; } @Override public Type getRawType() { return raw; } @Override public Type getOwnerType() {return null;}}

3.2 生成 Gson 需要的泛型

3.2.1 解析 data 是 Object 的情况public static Result fromJsonObject(Reader reader, Class clazz) { Type type = new ParameterizedTypeImpl(Result.class, new Class[]{clazz}); return GSON.fromJson(reader, type);}

3.2.2 解析 data 是 Array 的情况

是 Array 的情况要比是 Object 的情况多那么一步。

public static Result fromJsonArray(Reader reader, Class clazz) { // 生成 List 中的 List Type listType = new ParameterizedTypeImpl(List.class, new Class[]{clazz}); // 根据 List 生成完整的 Result Type type = new ParameterizedTypeImpl(Result.class, new Type[]{listType}); return GSON.fromJson(reader, type);}

本次代码较少,不提供源码

虽然这篇博客是以 Gson 为例,但从上面的内容可以看出实际上和 Gson 关系不大,主要的内容还是 Java 的泛型基础,所以这种封装的方法同样适用于其它的框架。

最后借这次机会给安利一个简易的泛型生成库 TypeBuilder,其最初实现的目的就是让大家快速的生成泛型信息,同时也会作一些参数检查,保证正确性。

用上面的代码给大家举个例子:

public static Result fromJsonArray(Reader reader, Class clazz) { Type type = TypeBuilder .newInstance(Result.class) .beginSubType(List.class) .addTypeParam(clazz) .endSubType() .build(); return GSON.fromJson(reader, type);}public static Result fromJsonObject(Reader reader, Class clazz) { Type type = TypeBuilder .newInstance(Result.class) .addTypeParam(clazz) .build(); return GSON.fromJson(reader, type);}


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有