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<Collection<Foo>>(){}.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
----------------------------------------------多做多解决多总结-----------------------------------