/**
*
*/
package com.googlecode.objectify.repackaged.gentyref;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.HashMap;
import java.util.Map;
/**
* Mapping between type variables and actual parameters.
*
* @author Wouter Coekaerts <wouter@coekaerts.be>
*/
class VarMap {
private final Map<TypeVariable<?>, Type> map = new HashMap<>();
/**
* Creates an empty VarMap
*/
VarMap() {
}
/**
* Creates a VarMap mapping the type parameters of the class used in <tt>type</tt> to their actual value.
*/
VarMap(ParameterizedType type) {
// loop over the type and its generic owners
do {
Class<?> clazz = (Class<?>)type.getRawType();
Type[] arguments = type.getActualTypeArguments();
TypeVariable<?>[] typeParameters = clazz.getTypeParameters();
// since we're looping over two arrays in parallel, just to be sure check they have the same size
if (arguments.length != typeParameters.length) {
throw new IllegalStateException("The given type [" + type + "] is inconsistent: it has " +
arguments.length + " arguments instead of " + typeParameters.length);
}
for (int i = 0; i < arguments.length; i++) {
add(typeParameters[i], arguments[i]);
}
Type owner = type.getOwnerType();
type = (owner instanceof ParameterizedType) ? (ParameterizedType)owner : null;
} while (type != null);
}
void add(TypeVariable<?> variable, Type value) {
map.put(variable, value);
}
void addAll(TypeVariable<?>[] variables, Type[] values) {
assert variables.length == values.length;
for (int i = 0; i < variables.length; i++) {
map.put(variables[i], values[i]);
}
}
VarMap(TypeVariable<?>[] variables, Type[] values) {
addAll(variables, values);
}
Type map(Type type) {
if (type instanceof Class) {
return type;
} else if (type instanceof TypeVariable) {
TypeVariable<?> tv = (TypeVariable<?>) type;
if (!map.containsKey(type)) {
throw new UnresolvedTypeVariableException(tv);
}
return map.get(type);
} else if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
return new ParameterizedTypeImpl((Class<?>)pType.getRawType(), map(pType.getActualTypeArguments()), pType.getOwnerType() == null ? pType.getOwnerType() : map(pType.getOwnerType()));
} else if (type instanceof WildcardType) {
WildcardType wType = (WildcardType) type;
return new WildcardTypeImpl(map(wType.getUpperBounds()), map(wType.getLowerBounds()));
} else if (type instanceof GenericArrayType) {
return GenericArrayTypeImpl.createArrayType(map(((GenericArrayType)type).getGenericComponentType()));
} else {
throw new RuntimeException("not implemented: mapping " + type.getClass() + " (" + type + ")");
}
}
Type[] map(Type[] types) {
Type[] result = new Type[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = map(types[i]);
}
return result;
}
}