• Java反射--基于ParameterizedType实现泛型类,参数化类型


    一、引子:

    项目中使用Gson的反序列化将json转化成具体的对象,具体方法是:

    package com.google.gson;下的反序列化方法

    1 public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException{
    2   ......
    3 }

    参数<T> :the type of the desired object

    参数json:要被反序列化的json数据;

    参数typeOfT:指定的通用类型的src。可以通过 Type typeOfT = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();获得;

    边对象:使用了泛型类

    1 public class CtiEdgeT<T,V> {
    2     private String id;
    3     //顶点
    4     private T inVertex;
    5     //对应点
    6     private V outVertex;
    7    ......
    8 }

    最开始考虑使用具体的model作为参数,例如CtiEdgeT<DomainVertex,IpVertex> 具体类型(DomainVertex,IpVertex)做为参数,通过gson反序列化获得具体类型的CtiEdgeT<SampleVertex,IpVertex>对象,例如:

     1  private boolean saveEdgeToGraph(String msg, String inType, String outType) {
     2         boolean flag = false;
     3         switch (inType){
     4             case Constant.SAMPLE_LABEL:{
     5                 switch (outType){
     6                     case Constant.IP_LABEL:{
     7                         Type type = new TypeToken<CtiEdgeT<SampleVertex,IpVertex>>() {
     8                         }.getType();
     9                         CtiEdgeT<SampleVertex,IpVertex> edge =  JsonUtil.getJson().fromJson(msg, type);
    10                         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);                     
    11                         break;
    12                     }
    13                     case Constant.DOMAIN_LABEL:{
    14                         Type type = new TypeToken<CtiEdgeT<SampleVertex,DomainVertex>>() {
    15                         }.getType();
    16                         CtiEdgeT<SampleVertex,DomainVertex> edge =  JsonUtil.getJson().fromJson(msg, type);
    17                         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);                        
    18                         break;
    19                     }
    20                     。。。。。。
    21                 }
    22             }
    23         }
    24     }

    本项目中就有20+种数据,即20+个model,这样做导致的结果就是如果有很多不同的边CtiEdgeT<T,V>,将会写大量的冗余代码。

    二、解决方案:

    可以通过 ParameterizedType 这个接口实现泛型类,参数化类型,参考这篇文章: https://www.jianshu.com/p/b1ad2f1d3e3e

    具体实现如下:

    EdgeParameterTypeImpl:
     1 import java.lang.reflect.ParameterizedType;
     2 import java.lang.reflect.Type;
     3 
     4 public class EdgeParameterTypeImpl implements ParameterizedType {
     5 
     6     //
     7     private Class ctiEdgeT ;
     8     //顶点
     9     private Class inVertex ;
    10     //对应点
    11     private Class outVertex ;
    12     
    13     public EdgeParameterTypeImpl(Class ctiEdgeT,Class inVertex,Class outVertex) {
    14         this.ctiEdgeT = ctiEdgeT ;
    15         this.inVertex = inVertex ;
    16         this.outVertex = outVertex ;
    17     }
    18     
    19     @Override
    20     public Type[] getActualTypeArguments() {
    21         return new Type[]{inVertex,outVertex};
    22     }
    23 
    24     @Override
    25     public Type getRawType() {
    26         return ctiEdgeT;
    27     }
    28 
    29     @Override
    30     public Type getOwnerType() {
    31         return null;
    32     }
    33   
    34 }
     边 CtiEdgeT<T,V>:
     1 public class CtiEdgeT<T,V> {
     2     private String id;
     3     //顶点
     4     private T inVertex;
     5     //对应点
     6     private V outVertex;
     7 
     8     public String getId() {
     9         return id;
    10     }
    11 
    12     public void setId(String id) {
    13         this.id = id;
    14     }
    15 
    16     public T getInVertex() {
    17         return inVertex;
    18     }
    19 
    20     public void setInVertex(T inVertex) {
    21         this.inVertex = inVertex;
    22     }
    23 
    24     public V getOutVertex() {
    25         return outVertex;
    26     }
    27 
    28     public void setOutVertex(V outVertex) {
    29         this.outVertex = outVertex;
    30     }
    31 }

    通过参数化泛型解决,传入的具体model类作为参数,反序列化得到具体的边

     1 private boolean saveEdgeToGraph(String msg, String inType, String outType) {
     2         boolean flag = false;
     3         Class<?> inVertex = Constant.vertexClassMap.get(inType); //inType : SAMPLE_LABEL
     4         Class<?> outVertex = Constant.vertexClassMap.get(outType); //outType : IP_LABEL
     5         EdgeParameterTypeImpl type = new EdgeParameterTypeImpl(CtiEdgeT.class, inVertex, outVertex);
     6         @SuppressWarnings("rawtypes")
     7         CtiEdgeT edge =  JsonUtil.getJson().fromJson(msg,type);
     8         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);       
     9         return flag;
    10     }

    从vertexClassMap中取对应的具体model
     1 public class Constant {
     2     @SuppressWarnings("rawtypes")
     3     public static Map<String,Class> vertexClassMap = new HashMap<String,Class>();
     4     
     5     static{
     6         try {
     7             vertexClassMap.put(SAMPLE_LABEL,SampleVertex.class);
     8             vertexClassMap.put(IP_LABEL,IpVertex.class);
     9             vertexClassMap.put(DOMAIN_LABEL,DomainVertex.class);
    10             。。。。。。
    11             }
    12         }
    13     }    

    通过追踪代码:CtiEdgeT edge = JsonUtil.getJson().fromJson(msg,type);可以发现type的源码

    1   TypeToken(Type type) {
    2     this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
    3     this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
    4     this.hashCode = this.type.hashCode();
    5   }
     1   public static Type canonicalize(Type type) {
     2     if (type instanceof Class) {
     3       Class<?> c = (Class<?>) type;
     4       return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
     5 
     6     } else if (type instanceof ParameterizedType) {
     7       ParameterizedType p = (ParameterizedType) type;
     8       return new ParameterizedTypeImpl(p.getOwnerType(),
     9           p.getRawType(), p.getActualTypeArguments());
    10 
    11     }
    12     ......
    13   }

    上面标红的代码会执行具体model的实现类的方法,得到具体的类型。

    三、拓展点:

    关于ParameterizedType 的解析可以 参考这篇文章: https://blog.csdn.net/a327369238/article/details/52622331

     1 public class ParameterTest {
     2     public static void main(String[] args) {
     3         Method method = null;
     4         try {
     5             //这里的第二个参数,和getRawType()意义类似
     6             method = new ParameterTest().getClass().getMethod("test", HashMap.class);
     7         } catch (NoSuchMethodException e) {
     8             e.printStackTrace();
     9         }
    10         Type[] types = method.getGenericParameterTypes();
    11         ParameterizedType ptype = (ParameterizedType) types[0];
    12         Type rawType = ptype.getRawType();
    13         System.out.println("最外层<>前面那个类型 rawType:"+rawType);
    14         Type type = ptype.getActualTypeArguments()[0];
    15         Type type1 = ptype.getActualTypeArguments()[1];
    16         System.out.println("泛型 type:"+type);
    17         System.out.println("泛型 type1:"+type1);
    18         Type ownerType = ptype.getOwnerType();
    19         System.out.println("ownerType:"+ownerType);
    20         //type是Type类型,但直接输出的不是具体Type的五种子类型,
    21        //而是这五种子类型以及WildcardType具体表现形式
    22         System.out.println("泛型 type name:"+type.getClass().getName());
    23     }
    24     public void test(HashMap<String,Integer> a){
    25     }
    26 }

     结果:

    1 最外层<>前面那个类型 rawType:class java.util.HashMap
    2 泛型 type:class java.lang.String
    3 泛型 type1:class java.lang.Integer
    4 ownerType:null
    5 泛型 type name:java.lang.Class

     因此 EdgeParameterTypeImpl 中的

     public Type getRawType() {   return ctiEdgeT;} 得到 边ctiEdgeT,而边 CtiEdgeT<T,V> 是参数是泛型,

     public Type[] getActualTypeArguments() { return new Type[]{inVertex,outVertex};} 得到 参数 inVertex,outVertex

    ----------------------------------------------多做多解决多总结-----------------------------------

  • 相关阅读:
    Hive安装教程
    HBase安装教程
    Hadoop集群搭建
    Redis集群安装详细步骤
    Python绘图工具turtle库的使用
    python程序语法元素分析
    Selenium请求库爬取京东商品实例
    python爬虫入门
    python入门
    pytest fixture场景一:参数传入
  • 原文地址:https://www.cnblogs.com/sqy123/p/9707952.html
Copyright © 2020-2023  润新知