TypeReference>
对象动态构造TypeReference>>
对象有以下类定义:
class Result {private long code;private T data;
}class People {private String name;
}
实例化以下对象:
Result> result = new Result<>();
List peopleList = new ArrayList<>();
People xiaoHong = new People("小红");
People xiaoMing = new People("小明");
peopleList.add(xiaoHong);
peopleList.add(xiaoMing);
result.setData(peopleList);
其对应的JSON字符串为:
{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}
下面使用jackson的TypeReference来反序列化字符串为以上的对象:
String jsonStr = "{\"code\":0,\"data\":[{\"name\":\"小红\"},{\"name\":\"小明\"}]}";
TypeReference>> typeReference = new TypeReference>>() {};
ObjectMapper objectMapper = new ObjectMapper();
Result> listResult = objectMapper.readValue(jsonStr, typeReference);
当我们构造http客户端的时候,有时候不想让用户看到类似Result
这样的返回,只想给用户>
List
这样的数据,那怎么动态构造TypeReference呢?
假设我们提供了一个http客户端工具,它的定义是这样的。
class HttpClient {public T get(String url, Map params, TypeReference typeR) {//获取jsonStr, 假设这里获取到的是:{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}String jsonStr = execute(url, params);//todo 解析为枚举类型,下面会讲解如何实现}
}
假设我们这样调用HttpClient:
HttpClient client = new HttpClient();
//注意这里的TypeReference的泛型
List result = client.get("http://xxxx", params, new TypeReference>());
额额额???为啥不是TypeReference
???
这就是我们要达到的目的,即用户不关注外层包裹的Result,只需要指定实际想要的类型即可。下面我们来看下如何实现。
首先我们实现一个ParameterizedType的子类,至于这个类的作用请往下看:
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;public class ParameterizedTypeImpl implements ParameterizedType, Serializable {private final Type[] actualTypeArguments;private final Type ownerType;private final Type rawType;public ParameterizedTypeImpl(Type[] actualTypeArguments, Type ownerType, Type rawType) {this.actualTypeArguments = actualTypeArguments;this.ownerType = ownerType;this.rawType = rawType;}@Overridepublic Type[] getActualTypeArguments() {return this.actualTypeArguments;}@Overridepublic Type getRawType() {return this.rawType;}@Overridepublic Type getOwnerType() {return this.ownerType;}
}
我们来解释一下这个类,先看一下这个类的继承链:
ParameterizedTypeImpl implements ParameterizedType extends Type
在java9之前jdk是包含了ParameterizedTypeImpl的实现的,但在jdk9及以后就没了,所以保险起见我们自己需要实现一下。
我们再看一下TypeReference的定义:
public abstract class TypeReference implements Comparable> {protected final Type _type;protected TypeReference() {Type superClass = this.getClass().getGenericSuperclass();if (superClass instanceof Class) {throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");} else {this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];}}public Type getType() {return this._type;}public int compareTo(TypeReference o) {return 0;}
}
这里的_type
成员变量即ParameterizedTypeImpl类型。
我们继续看ParameterizedTypeImpl几个成员变量的意思:(此处以:new TypeReference
为例)
rowType=Result.class
,即原始的类是什么actualTypeArguments=new Type[]{List.class}
,为什么是数组类型,是因为泛型里面可以放多个类型,我可以这么放:Result,Set>
,那么这里的actualTypeArguments=new Type[]{List.class,Set}
,因为是一个Type数组,而每个Type又是一个ParameterizedType,所以可以向下继续查看(嵌套)。I.S
,则S
的ownerType=I
class HttpClient {public T get(String url, Map params, TypeReference typeR) {//获取jsonStr, 假设这里获取到的是:{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}String jsonStr = execute(url, params);ObjectMapper objectMapper = new ObjectMapper();//在此处偷梁换柱TypeReference> resultType = new TypeReference>>() {@Overridepublic Type getType() {//在外层再包一层Result,就是所谓的动态构造,是不是很简单!!!return new ParameterizedTypeImpl(new Type[]{typeR.getType()},null, Result.class);}};Result listResult = objectMapper.readValue(jsonStr, resultType);//此处省略了一下异常判断,不可直接这么使用return listResult.getData();}
}
然后我们就可以这么调用了:
HttpClient client = new HttpClient();
//注意这里的TypeReference的泛型
List result = client.get("http://xxxx", params, new TypeReference>());
OK,完结!