美文网首页
服务器接口的泛型封装

服务器接口的泛型封装

作者: 陆元伟 | 来源:发表于2019-05-21 18:07 被阅读0次

服务器接口的泛型封装

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]]

相关文章

  • 服务器接口的泛型封装

    服务器接口的泛型封装 APP和服务器交互时,一般会约定服务器返回特定的数据结构。比如一般会返回如下结构。 code...

  • 泛型

    1.什么是泛型? 2.为什么需要泛型? 3.泛型类、接口 泛型类注意事项: 从泛型类派生子类 泛型接口 泛型接口的...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • class 类

    基本用法 构造函数和this 继承 抽象类 接口(TypeScript 独有) 属性的封装 泛型

  • 【面向对象】泛型广泛应用封装

    实际工作中,我们经常对接口调用进行封装,利用泛型返回结果值。 1. 封装函数,统一的返回结果值 所有的调用接口封装...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • 泛型

    问题引入 泛型引入 如果使用泛型类或接口的时候,用Object 通配符 不设置方法类型 泛型接口 定义接口泛型 在...

  • 泛型

    一、泛型类、泛型接口和泛型方法1、泛型接口的定义: 2、两种泛型类的定义:(1) (2) 3、泛型方法的定义,可以...

  • ts 泛型

    函数泛型 接口,类泛型

  • Swift 运用协议泛型封装网络层

    Swift 运用协议泛型封装网络层 Swift 运用协议泛型封装网络层

网友评论

      本文标题:服务器接口的泛型封装

      本文链接:https://www.haomeiwen.com/subject/vnfszqtx.html