Posts Tagged ‘ Generics

How to get Generic Metadata from a Class at Runtime

Like Annotations, Generics are also a runtime metadata that you can process at the run time.

Here you can see how to traverse the runtime information to get this information. You Can simply traverse the inheritance tree ofr the class and get the metadata of the generic definition. Somthing like

 public static Type[] getGenericDefinitons(Class classFrom, Class class1) ;
Type[] types=getGenericDefinitons(MockClass1.class,GenericInterface.class);//[String.class,Long.class,Integer.class] expected

First The Sample Cases :


public interface GenericInterface <T,K,L>{}

 public interface MockClass1 extends GenericInterface<String,Long,Integer>{}
 public interface MockClass11<T,K,L> extends GenericInterface<T,K,L>{}
 public interface MockClass12 extends MockClass11<String,Long,Integer>{}
 public interface MockClass2 extends MockClass1{}

 public class MockClass3 implements GenericInterface<String,Long,Integer>{}
 public class MockClass4 extends MockClass3{}

 public class GenericClass <T,K,L>{}
 public class AMockClass2 extends AMockClass1{}
 public class AMockClass1 extends GenericClass<String,Long,Integer>{}

And the java class metadata traverser to retrieve the Generic Information


public class Utils {

 /**Get the Generic definition from a class for given class with given index
 * @param clz Implementing class
 * @param class1 class with generic definition
 * @param index generic index
 *  @return null if not found
 * */

 public static Type getGenericDefiniton( Class clz, Class class1, int index) {
 Type[] t = getGenericDefinitons(clz, class1);
 if (t != null && t.length > index)
 return t[index];
 return null;

 }
 /**Get the Generic definitions from a class for given class
 * @param clz Implementing class
 * @param class1 class with generic definition
 * @return null if not found
 * */
 public static Type[] getGenericDefinitons(Class clz, Class class1) {
 Type[] t = null;
 while (clz != null) {

 t = getGenericDefinitonsThis(clz, class1);
 if (t != null)
 return t;
 Class[] interfaces = clz.getInterfaces();
 for (Class class2 : interfaces) {
 t = getGenericDefinitonsThis(class2, class1);
 if (t != null)
 return t;
 }
 clz = clz.getSuperclass();
 }
 return t;
 }
 /**Get the Generic definitions from a class for given class without looking super classes
 * @param clz Implementing class
 * @param class1 class with generic definition
 * @return null if not found
 * */
 public static Type[] getGenericDefinitonsThis(Class classFrom, Class class1) {

 Type[] genericInterfaces = classFrom.getGenericInterfaces();
 for (Type type : genericInterfaces) {
 if (type instanceof ParameterizedType) {
 ParameterizedType pt = (ParameterizedType) type;

 if (class1.isAssignableFrom((Class) pt.getRawType())) {
 Type[] actualTypeArguments = pt.getActualTypeArguments();
 return actualTypeArguments;
 }
 }

 }
 // check if it if available on generic super class
 Type genericSuperclass = classFrom.getGenericSuperclass();
 if (genericSuperclass instanceof ParameterizedType) {
 ParameterizedType pt = (ParameterizedType) genericSuperclass;

 if (class1.equals(pt.getRawType())) {
 Type[] actualTypeArguments = pt.getActualTypeArguments();
 return actualTypeArguments;
 }
 }
 return null;

 }

}

And the test case

PS: This class is not tested for Multi-dimensional Generic Definitions


public class UtilsTest {
 @Test
 public void simpleInterfaceExtend(){
 Type[] genericDefinitons = Utils.getGenericDefinitons(MockClass1.class, GenericInterface.class);
 compareResults(genericDefinitons);
 }

 @Test
 public void simpleInterfaceExtend2(){

 Type[] genericDefinitons = Utils.getGenericDefinitons(MockClass2.class, GenericInterface.class);
 compareResults(genericDefinitons);
 }
 @Test
 public void simpleInterfaceExtend3(){

 Type[] genericDefinitons = Utils.getGenericDefinitons(MockClass12.class, GenericInterface.class);
 compareResults(genericDefinitons);
 }
 @Test
 public void simpleInterfaceImplements(){
 Type[] genericDefinitons = Utils.getGenericDefinitons(MockClass3.class, GenericInterface.class);
 compareResults(genericDefinitons);
 }
 @Test
 public void simpleInterfaceImplements2(){

 Type[] genericDefinitons = Utils.getGenericDefinitons(MockClass4.class, GenericInterface.class);
 compareResults(genericDefinitons);
 }

 @Test
 public void simpleClassImplements(){
 Type[] genericDefinitons = Utils.getGenericDefinitons(AMockClass1.class, GenericClass.class);
 compareResults(genericDefinitons);
 }
 @Test
 public void simpleClassImplements2(){

 Type[] genericDefinitons = Utils.getGenericDefinitons(AMockClass2.class, GenericClass.class);
 compareResults(genericDefinitons);
 }

 private void compareResults(Type[] genericDefinitons) {
 assertEquals(String.class,genericDefinitons[0]);
 assertEquals(Long.class,genericDefinitons[1]);
 assertEquals(Integer.class,genericDefinitons[2]);
 }

}