/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Arrays; import java.util.HashSet; import org.beanfabrics.model.IListPM; import org.beanfabrics.model.MapPM; import org.beanfabrics.model.OperationPM; import org.beanfabrics.model.PresentationModel; public class Reflect { private static HashSet<String> s_processed = new HashSet<String>(); private static void describe(int level, Field field) { // get base and generic types, check kind Class<?> btype = field.getType(); Type gtype = field.getGenericType(); if (gtype instanceof ParameterizedType) { // list basic parameterized type information ParameterizedType ptype = (ParameterizedType)gtype; println(level, field.getName() + " is of parameterized type " + btype.getName()); // print list of actual types for parameters println(level, "using types ("); Type[] actuals = ptype.getActualTypeArguments(); for (int i = 0; i < actuals.length; i++) { if (i > 0) { print(" "); } Type actual = actuals[i]; if (actual instanceof Class) { print(((Class)actual).getName()); } else { print(actuals[i]); } } println(level, ")"); // analyze all parameter type classes for (int i = 0; i < actuals.length; i++) { Type actual = actuals[i]; if (actual instanceof Class) { analyze(level, (Class)actual); } } } else if (gtype instanceof GenericArrayType) { // list array type and use component type println(level, field.getName() + " is array type " + gtype); gtype = ((GenericArrayType)gtype).getGenericComponentType(); } else { // just list basic information println(level, field.getName() + " is of type " + btype.getName()); } // analyze the base type of this field analyze(level, btype); } private static void describeTypeVariable(int level, TypeVariable var) { println(level, "TypeVariable " + var.getName() + " (" + System.identityHashCode(var) + ")"); Type[] bounds = var.getBounds(); if (bounds != null && bounds.length > 0) { println(level, " is bounded:"); for (int i = 0; i < bounds.length; i++) { describeType(level + 1, bounds[i]); } } } private static void describeType(int level, Type type) { if (type == null) { println(level, "is null"); } else if (type instanceof Class) { describeClass(level, (Class)type); } else if (type instanceof ParameterizedType) { describeParameterizedType(level, (ParameterizedType)type); } else if (type instanceof TypeVariable) { describeTypeVariable(level, (TypeVariable)type); } else { throw new IllegalArgumentException("Can't describe type of type " + type.getClass().getName()); } } private static void describeParameterizedType(int level, ParameterizedType type) { println(level, "ParameterizedType has raw type:"); describeType(level + 1, type.getRawType()); println(level, "ParameterizedType has owner type:"); describeType(level + 1, type.getOwnerType()); println(level, "and has actual type arguments:"); Type[] args = type.getActualTypeArguments(); for (int i = 0; i < args.length; i++) { describeType(level + 1, args[i]); } } private static void describeClass(int level, Class type) { println(level, "// Class of Class is " + type.getClass().getName()); analyze(level, type); } private static void analyze(int level, Class<?> clas) { // substitute component type in case of an array if (clas.isArray()) { clas = clas.getComponentType(); } // make sure class should be expanded String name = clas.getName(); if (!clas.isPrimitive() && !clas.isInterface() //&& !name.startsWith("java.lang.") && !s_processed.contains(name)) { // print introduction for class s_processed.add(name); println(level, "Class " + clas.getName()); // process each field of class // String indent = lead + ' '; // Field[] fields = clas.getDeclaredFields(); // if ( fields != null && fields.length>0) { // System.out.println(lead + "having fields:" ); // for (int i = 0; i < fields.length; i++) { // Field field = fields[i]; // if (!Modifier.isStatic(field.getModifiers())) { // describe(indent, field); // } // } // } Type sups = clas.getGenericSuperclass(); if (sups != null) { println(level, "extending superclass:"); describeType(level + 1, sups); } Type[] supgi = clas.getGenericInterfaces(); if (supgi != null && supgi.length > 0) { println(level, "implementing interfaces:"); for (int i = 0; i < supgi.length; ++i) { describeType(level + 1, supgi[i]); } } } else if (clas.isInterface() //&& !name.startsWith("java.lang.") && !s_processed.contains(name)) { s_processed.add(name); println(level, "Interface " + clas.getName()); TypeVariable[] params = clas.getTypeParameters(); if (params != null && params.length > 0) { println(level, "having type parameters:"); // process each type parameter of class for (int i = 0; i < params.length; i++) { TypeVariable tvar = params[i]; if (true) { describeTypeVariable(level + 1, tvar); } } } Type sups = clas.getGenericSuperclass(); if (sups != null) { println(level, "extending superclass:"); describeType(level + 1, sups); } Type[] supgi = clas.getGenericInterfaces(); if (supgi != null && supgi.length > 0) { println(level, "extending interfaces:"); for (int i = 0; i < supgi.length; ++i) { describeType(level + 1, supgi[i]); } } } else { println(level, "Won't describe " + clas.getName()); } } private static void print(Object str) { System.out.print(String.valueOf(str)); } private static void println(int level, String str) { char[] spaces = new char[level]; Arrays.fill(spaces, ' '); System.out.println(level + new String(spaces) + str); } public static void main(String[] args) throws Exception { analyze(1, Iterable.class); System.out.println("Ready."); } private static interface MyList extends IListPM<OperationPM> { } private static class MyMap extends MapPM<String, OperationPM> { } private static interface IGelb<G> { G getG(); } private static interface IBlau<B> { B getB(); } private static class MapCell2<G1, K1, V1 extends PresentationModel> extends MapPM<K1, V1> implements IGelb<G1> { public G1 getG() { return null; } } private static class MyMap2 extends MapCell2<Integer, String, OperationPM> { } }