package edu.isi.bmkeg.utils;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import java.util.TreeMap;
/**
* <br>Copyright (c) 2007-2008, Regents of the University of Colorado
* <br>All rights reserved.
*/
public class ReflectionUtils {
/**
* Perform an unchecked cast based on a type parameter.
*
* @param <T> The type to which the object should be cast.
* @param o The object.
* @return The object, cast to the given type.
*/
@SuppressWarnings("unchecked")
public static <T> T uncheckedCast(Object o) {
return (T)o;
}
public static interface TypeArgumentDelegator {
public Map<String,Type> getTypeArguments(Class<?> genericType);
}
public static <T> Type getTypeArgument(Class<T> genericType, String typeParameterName, T obj) {
Map<String,Type> typeArguments = getTypeArguments(genericType, obj);
return typeArguments == null ? null : typeArguments.get(typeParameterName);
}
/**
* Try to find the instantiation of all of genericTypes type parameters in objs class.
*
* @param genericType the generic supertype of objs class
* @param obj an instantiation of a subclass of genericType. All of genericTypes type
* parameters must have been instantiated in the inheritance hierarchy.
* @return a map of genericTypes type parameters (their name in the source code) to
* the type they are instantiated as in obj
*/
public static Map<String,Type> getTypeArguments(Class<?> genericType, Object obj) {
if (obj instanceof TypeArgumentDelegator) {
return ((TypeArgumentDelegator)obj).getTypeArguments(genericType);
}
Map<String,Type> typeMap = new TreeMap<String,Type>();
return getTypeArguments(genericType, obj.getClass(), typeMap);
}
public static boolean isAssignableFrom(Type type1, Type type2) {
if (type1 instanceof Class<?> && type2 instanceof Class<?>) {
return ((Class<?>)type1).isAssignableFrom((Class<?>)type2);
} else {
return type1.equals(type2);
}
}
private static Map<String,Type> getTypeArguments(Class<?> genericType, Type type, Map<String,Type> typeMap) {
if( type instanceof ParameterizedType ) {
return getTypeArguments(genericType, (ParameterizedType)type, typeMap);
} else if( type instanceof Class<?> ) {
return getTypeArguments(genericType, (Class<?>) type, typeMap);
} else {
throw new IllegalArgumentException();
}
}
private static Map<String,Type> getTypeArguments(Class<?> genericType, Class<?> classType, Map<String,Type> typeMap) {
if( genericType.isInterface() ) {
for( Type interfaceType : classType.getGenericInterfaces() ) {
Map<String,Type> result = getTypeArguments(genericType, interfaceType, typeMap);
if( result != null )
return result;
}
}
Type superType = classType.getGenericSuperclass();
if( superType != null ) {
return getTypeArguments(genericType, superType, typeMap);
}
return null;
}
private static Map<String,Type> getTypeArguments(Class<?> genericType, ParameterizedType paramType, Map<String,Type> typeMap) {
Class<?> rawType = (Class<?>) paramType.getRawType();
if( rawType == genericType ) {
// found it!
TypeVariable<?> typeVars[] = rawType.getTypeParameters();
Type actualTypes[] = paramType.getActualTypeArguments();
Map<String,Type> result = new TreeMap<String,Type>();
for( int i=0; i<actualTypes.length; i++ ) {
while( actualTypes[i] != null && actualTypes[i] instanceof TypeVariable<?> ) {
String key = typevarString((TypeVariable<?>) actualTypes[i]);
if( typeMap.containsKey(key) )
actualTypes[i] = typeMap.get(key);
else
actualTypes[i] = null;
}
result.put(typeVars[i].getName(), actualTypes[i]);
}
return result;
} else {
TypeVariable<?> typeVars[] = rawType.getTypeParameters();
Type actualTypes[] = paramType.getActualTypeArguments();
for( int i=0; i<typeVars.length; i++ )
typeMap.put(typevarString(typeVars[i]), actualTypes[i]);
return getTypeArguments(genericType, paramType.getRawType(), typeMap);
}
}
private static String typevarString(TypeVariable<?> tv) {
return tv.getGenericDeclaration().toString() + " " + tv.getName();
}
}