服务器接口的泛型封装
APP和服务器交互时,一般会约定服务器返回特定的数据结构。比如一般会返回如下结构。
{
"code": 0,
"message": "Ok",
"data":数据
}
code一般双方约定好,表示成功或者失败或者其他,message,表示辅助信息,data表示服务器返回的数据,可能是int,string,对象,甚至数组
由于data的不确定性。因此我们解析最好就用泛型表示
对应的实体类
public class ServerResponse<T> {
public int code;
public String message;
public T data;
}
但是因为里面有个泛型。直接通过Gson的 fromJson(String json, Class<T> classOfT)方法解析,解析其他字段会正常解析,data则会解析成LinkedTreeMap类型,
//模拟数据类
public class Data {
public int a=1;
public String b="123";
@Override
public String toString() {
return "Data [a=" + a + ", b=" + b + "]";
}
}
public static void main(String[] args) throws Exception {
ServerResponse<Data> respones = new ServerResponse<>();
Data d=new Data();
d.a =1;
d.b = "123";
respones.data=d;
respones.code = 200;
Gson gson = new Gson();
ServerResponse respones2= gson.fromJson(gson.toJson(respones), ServerResponse.class);
System.out.println(respones2.data.getClass());
}
输出信息
class com.google.gson.internal.LinkedTreeMap
如果在解析时加个类型,
public static void main(String[] args) throws Exception {
ServerResponse<Data> respones = new ServerResponse<>();
Data d=new Data();
d.a =1;
d.b = "123";
respones.data=d;
respones.code = 200;
Gson gson = new Gson();
//加个类型
ServerResponse<Data> respones2= gson.fromJson(gson.toJson(respones), ServerResponse.class);
System.out.println(respones2.data.getClass());
}
则直接报错
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to test.Data
at test.Test.main(Test.java:20)
想要解析泛型,则需要用fromJson(String json, Type typeOfT)重载方法
接口ParameterizedType继承了Type接口,该接口
public interface ParameterizedType extends Type {
/**
* 返回泛型参数类型
*/
Type[] getActualTypeArguments();
/**
*返回自己的类型
*/
Type getRawType();
/**
*
*/
Type getOwnerType();
}
利用此接口,我们可以把泛型参数类型传递进去,Gson就能正确解析出来。封装如下
/**
* @param gsonStr json字符串
* @param clazz 返回的类型
* @param <T>
* @return 解析错误返回null
*/
public static <T> T fromJson(String gsonStr, Class<T> clazz, Class<?> typeClazz) {
Gson gson = new Gson();
try {
Type objectType = type(clazz, typeClazz);
return gson.fromJson(gsonStr, objectType);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
static ParameterizedType type(final Class raw, final Type... args) {
return new ParameterizedType() {
public Type getRawType() {
return raw;
}
public Type[] getActualTypeArguments() {
return args;
}
public Type getOwnerType() {
return null;
}
};
}
代码修改如下
public static void main(String[] args) throws Exception {
ServerResponse<Data> respones = new ServerResponse<>();
Data d=new Data();
d.a =1;
d.b = "123";
respones.data=d;
respones.code = 200;
Gson gson = new Gson();
//调用封装的fromJson,传递自己的类型和泛型类型
ServerResponse<Data> respones2= GsonUtil.fromJson(gson.toJson(respones), ServerResponse.class,Data.class);
System.out.println(respones2.data.getClass());
System.out.println(respones2.data.toString());
}
打印信息如下。已经正确解析出来了。
class test.Data
Data [a=1, b=123]
继续。由于要通用。因此我们调用服务器接口后回调返回的类型也要用泛型,接口如下
public interface IHttpCallBack<T> {
/**
* 请求成功的回调
*
* @param data 请求成功返回的信息
*/
void onSuccess(T data);
/**
* 请求失败的回调
*
* @param e 请求失败的信息
*/
void onFail(Exception e);
}
一般封装接口都会如此。
//url.接口地址,callback,回调的接口
public static <T> void request(String url,IHttpCallBack<T> callBack) {
...
//假设这个是服务器返回的数据,我们要根据这个解析到
String gson = "";
...
}
假设我们已经获取到服务器返回的gson了。根据封装好的GsonUtil.fromJson(ServerResponse.class,type)
可以解析泛型,但是问题是这个地方,泛型的类型是什么,我们都不知道。
这又有另外一个问题。我们如何得知一个类它的泛型的类型?如果我们知道什么数据类型了,只要调用GsonUtil.fromJson(ServerResponse.class,type)
就可以了。代码如下
public static Class<?> getParameterizedType(Class<?> clazz,boolean isInterface){
//返回表示此 Class 所表示的实体类的 直接父类 的 Type。注意,是直接父类
Type type = clazz.getGenericSuperclass();
try {
//如果是接口
if (isInterface) {
type = clazz.getGenericInterfaces()[0];
}
// 判断 是否泛型
if (type instanceof ParameterizedType) {
// 返回表示此类型实际类型参数的Type对象的数组.
// 当有多个泛型类时,数组的长度就不是1了
Type[] ptype = ((ParameterizedType) type).getActualTypeArguments();
Type t = ptype[0];
if(t instanceof Class) {
Class<?> c = (Class) ptype[0];
return c;
}else if(t instanceof ParameterizedType){
return (Class)((ParameterizedType) t).getRawType();
}
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
request封装如下
//假设s就是服务器返回的数据
public static <T> void request(String s,IHttpCallBack<T> callBack) {
Class paramsClass = getParameterizedType(callBack.getClass(),true);
ServerResponse<T> response;
if(paramsClass!=null) {
response=GsonUtil.fromJson(s, ServerResponse.class, paramsClass);
}else {
response=GsonUtil.fromJson(s, ServerResponse.class);
}
callBack.onSuccess(response.data);
}
测试代码
public static void main(String[] args) throws Exception {
ServerResponse<Data> respones = new ServerResponse<>();
Data d=new Data();
d.a =1;
d.b = "123";
respones.data=d;
respones.code = 200;
Gson gson = new Gson();
IHttpCallBack<Data> callback = new IHttpCallBack<Data>() {
@Override
public void onSuccess(Data data) {
System.out.println("data:"+data.toString());
}
@Override
public void onFail(Exception e) {
}
};
request(GsonUtil.toJson(respones),callback);
}
打印信息如下。
data:Data [a=1, b=123]
如果ServerResponse 里面的data是List集合的话,,那么上述方法还是解析不了成想要的对象
测试代码
public static void main(String[] args) throws Exception {
ServerResponse<List<Data>> respones = new ServerResponse<>();
List<Data> list=new ArrayList<>();
Data d=new Data();
d.a =1;
d.b = "123";
list.add(d);
respones.data=list;
respones.code = 200;
IHttpCallBack<List<Data>> callback = new IHttpCallBack<List<Data>>() {
@Override
public void onSuccess(List<Data> data) {
System.out.println("data:"+data.toString());
System.out.println("data:"+data.get(0).getClass());
}
@Override
public void onFail(Exception e) {
}
};
request(GsonUtil.toJson(respones),callback);
}
抛出异常
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
at test.Test.getParameterizedType(Test.java:179)
at test.Test.main(Test.java:46)
前面这个获取泛型参数类型的方法。
public static Class<?> getParameterizedType(Class<?> clazz,boolean isInterface){
//返回表示此 Class 所表示的实体类的 直接父类 的 Type。注意,是直接父类
Type type = clazz.getGenericSuperclass();
try {
if (isInterface) {
type = clazz.getGenericInterfaces()[0];
}
if (type instanceof ParameterizedType) {
Type[] ptype = ((ParameterizedType) type).getActualTypeArguments();
//这里抛异常,这里拿到的是个ParameterizedType,因为List里面也是个泛型
Class<?> c = (Class) ptype[0];
return c;
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
添加如下方法 ,我们再来回顾我们传入的参数 类型为 IHttpCallBack<List<Data>> ,其他List是IHttpCallBack的泛型。Data又是List的泛型。我们不但要获取IHttpCallBack里面的参数类型。还要获取List里面的参数类型
/**
* 获取clazz的泛型里面的泛型类型
* 如果clazz 传入的是 List<List<String>>
*返回String.class
* @param clazz 对象类型
* @param isInterface
* @return 泛型类型
*/
public static Class<?> getListParameterizedType(Class<?> clazz, boolean isInterface){
//返回表示此 Class 所表示的实体类的 直接父类 的 Type。注意,是直接父类
Type type = clazz.getGenericSuperclass();
try {
if (isInterface) {
type = clazz.getGenericInterfaces()[0];
}
// 判断 是否泛型
if (type instanceof ParameterizedType) {
// 返回表示此类型实际类型参数的Type对象的数组.
// 当有多个泛型类时,数组的长度就不是1了
Type[] ptype = ((ParameterizedType) type).getActualTypeArguments();
Type t = ptype[0];
if(t instanceof Class) {
Class<?> c = (Class) ptype[0];
return c;
}else if(t instanceof ParameterizedType){
return (Class)((ParameterizedType) t).getActualTypeArguments()[0];
}
return null;
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
那我们就要区别ServerRespose里面的data到底是集合类型还是一个对象类型。分别解析
//判断clazz是否是List或者实现了List接口
private static boolean isList(Class clazz) {
if(clazz == List.class) {
return true;
}
Class[] interfaces = clazz.getInterfaces();
if(interfaces==null||interfaces.length==0) {
return false;
}
for(Class<?> c:interfaces) {
if(c==List.class) {
return true;
}
}
return false;
}
解析也是不同的
/**
*
* @param json 字符串
* @param clazz 最外层的clazz
* @param typeClass List里面的泛型参数类型
* @return
*/
public static <T> T fromJsonType(String json, Class<T> clazz,Class typeClass) {
Gson gson = new Gson();
Type listType = new ParameterizedType() {
public Type getRawType() {
return List.class;
}
public Type[] getActualTypeArguments() {
return new Type[] { typeClass };
}
public Type getOwnerType() {
return null;
}
};
Type objectType = new ParameterizedType() {
public Type getRawType() {
return clazz;
}
public Type[] getActualTypeArguments() {
return new Type[] { listType };
}
public Type getOwnerType() {
return null;
}
};
return gson.fromJson(json, objectType);
}
request方法修改如下
public static <T> void request(String s,IHttpCallBack<T> callBack) throws Exception {
Class paramsClass = getParameterizedType(callBack.getClass(),true);
ServerResponse<T> response;
//如果有泛型类型
if(paramsClass!=null) {
//如果是集合泛型
if(isList(paramsClass)) {
//获取集合里面的泛型
Class type = getListParameterizedType(callBack.getClass(),true);
response=GsonUtil.fromJsonType(s,ServerResponse.class,type);
}else {
response=GsonUtil.fromJson(s, ServerResponse.class, paramsClass);
}
}else {
response=GsonUtil.fromJson(s, ServerResponse.class);
}
callBack.onSuccess(response.data);
}
输出结果
data:[Data [a=1, b=123]]
网友评论