package com.ontology2.bakemono.mapreduce;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
public class TypeDetective {
//
// Note that this doesn't scan interfaces, so you can get the type of an ArrayList<X>
// but not the type of a List<X>
//
public static Type[] sniffTypeParameters(Type that,Class targetClass) {
return sniffTypeParameters(that,targetClass,null);
}
public static Type[] sniffTypeParameters(Type that,Class targetClass,Map<TypeVariable,Type> typeParameters) {
if (typeParameters==null)
typeParameters=newHashMap();
else
typeParameters=newHashMap(typeParameters);
if(that==Object.class)
return null;
if(that instanceof ParameterizedType) {
ParameterizedType type=(ParameterizedType) that;
if (type.getRawType()==targetClass) {
Type[] arguments=type.getActualTypeArguments();
fillInTypeVariables(arguments,typeParameters);
return arguments;
} else if (type.getRawType() instanceof Class) {
Class clazz=(Class) type.getRawType();
TypeVariable[] variables=clazz.getTypeParameters();
Type[] values=type.getActualTypeArguments();
for(int i=0;i<values.length;i++) {
typeParameters.put(variables[i],values[i]);
}
return sniffTypeParameters(clazz.getGenericSuperclass(),targetClass,typeParameters);
}
}
if(that==targetClass)
throw new SelfAwareTool.NoGenericTypeInformationAvailable("I can't read the generic type parameter for ["+targetClass+"] unless you subclass it with a concrete class.");
if(that instanceof Class) {
Class type=(Class) that;
Type uber=type.getGenericSuperclass();
return sniffTypeParameters(uber,targetClass,typeParameters);
}
return null;
}
public static void fillInTypeVariables(Type[] thoseTypes,Map<TypeVariable,Type> typeParameters) {
for(int i=0;i<thoseTypes.length;i++) {
thoseTypes[i]=fillInTypeVariables(thoseTypes[i],typeParameters);
}
}
public static Type fillInTypeVariables(Type that,Map<TypeVariable,Type> typeParameters) {
if(that instanceof TypeVariable) {
if(typeParameters.containsKey(that)) {
return typeParameters.get(that);
}
}
if(that instanceof ParameterizedType) {
ParameterizedType pType=(ParameterizedType) that;
Type[] arguments=pType.getActualTypeArguments();
fillInTypeVariables(arguments,typeParameters);
return new ShadowedParameterizedType(pType,arguments);
}
return that;
}
}