package org.etk.reflect.core; import java.util.ArrayList; import java.util.List; import org.etk.reflect.api.ArrayTypeInfo; import org.etk.reflect.api.ClassTypeInfo; import org.etk.reflect.api.ParameterizedTypeInfo; import org.etk.reflect.api.TypeInfo; import org.etk.reflect.api.TypeVariableInfo; import org.etk.reflect.api.WildcardTypeInfo; public class Utils { public static TypeInfo resolve(ClassTypeInfo context, TypeInfo type) { if (type instanceof ClassTypeInfo) { return resolve(context, (ClassTypeInfo)type); } else if (type instanceof ParameterizedTypeInfo) { return resolve(context, (ParameterizedTypeInfo)type); } else if (type instanceof TypeVariableInfo) { return resolve(context, (TypeVariableInfo)type); } else if (type instanceof ArrayTypeInfo) { return resolve(context, (ArrayTypeInfo)type); } else if (type instanceof WildcardTypeInfo) { return resolve(context, (WildcardTypeInfo)type); } else { throw new UnsupportedOperationException("Cannot resolve type " + type + " with class " + type.getClass().getName()); } } static TypeInfo resolve(ClassTypeInfo context, final WildcardTypeInfo wildcardType) { final ArrayList<TypeInfo> resolvedUpperBounds = new ArrayList<TypeInfo>(); for (TypeInfo upperBound : wildcardType.getUpperBounds()) { resolvedUpperBounds.add(resolve(context, upperBound)); } final ArrayList<TypeInfo> resolvedLowerBounds = new ArrayList<TypeInfo>(); for (TypeInfo lowerBound : wildcardType.getLowerBounds()) { resolvedLowerBounds.add(resolve(context, lowerBound)); } return new AbstractWildcardType(((AbstractWildcardType)wildcardType).domain) { public List<TypeInfo> getUpperBounds() { return resolvedUpperBounds; } public List<TypeInfo> getLowerBounds() { return resolvedLowerBounds; } public Object unwrap() { throw new UnsupportedOperationException(); } }; } static TypeInfo resolve(ClassTypeInfo context, ArrayTypeInfo genericArrayType) { TypeInfo componentType = genericArrayType.getComponentType(); final TypeInfo resolvedComponentType = resolve(context, componentType); if (resolvedComponentType.equals(componentType)) { return genericArrayType; } else { return new AbstractArrayTypeInfo(((AbstractArrayTypeInfo)genericArrayType).domain) { public TypeInfo getComponentType() { return resolvedComponentType; } public Object unwrap() { throw new UnsupportedOperationException(); } }; } } static <T, M> TypeInfo resolve(ClassTypeInfo context, ClassTypeInfo classType) { return classType; } static <T, M> TypeInfo resolve(ClassTypeInfo context, final ParameterizedTypeInfo parameterizedType) { TypeInfo rawType = parameterizedType.getRawType(); if (rawType instanceof ClassTypeInfo) { List<? extends TypeInfo> typeArguments = parameterizedType.getTypeArguments(); final ArrayList<TypeInfo> resolvedTypeArguments = new ArrayList<TypeInfo>(); for (TypeInfo typeArgument : typeArguments) { TypeInfo resolvedTypeArgument = resolve(context, typeArgument); resolvedTypeArguments.add(resolvedTypeArgument); } return new AbstractParameterizedTypeInfo(((AbstractParameterizedTypeInfo)parameterizedType).domain) { public TypeInfo getRawType() { return parameterizedType.getRawType(); } public List<TypeInfo> getTypeArguments() { return resolvedTypeArguments; } public TypeInfo getOwnerType() { return parameterizedType.getOwnerType(); } public Object unwrap() { throw new UnsupportedOperationException(); } }; } else { throw new UnsupportedOperationException(); } } static <T, M> TypeInfo resolve(ClassTypeInfo context, TypeVariableInfo type) { return resolve((TypeInfo)context, type); } static <T, M> TypeInfo resolve(TypeInfo context, TypeVariableInfo typeVariable) { if (context instanceof ParameterizedTypeInfo) { ParameterizedTypeInfo parameterizedContext = (ParameterizedTypeInfo)context; TypeInfo rawType = parameterizedContext.getRawType(); if (!rawType.equals(typeVariable.getGenericDeclaration())) { TypeInfo resolvedTypeVariable = resolve(rawType, typeVariable); if (resolvedTypeVariable instanceof TypeVariableInfo) { if (resolvedTypeVariable.equals(typeVariable)) { return resolvedTypeVariable; } else { return resolve(context, (TypeVariableInfo)resolvedTypeVariable); } } else { return resolvedTypeVariable; } } else { int index = 0; for (TypeVariableInfo typeVariableParameter : typeVariable.getGenericDeclaration().getTypeParameters()) { TypeVariableInfo toto = typeVariableParameter; if (typeVariable.equals(toto)) { return parameterizedContext.getTypeArguments().get(index); } index++; } throw new AssertionError(); } } else if (context instanceof ClassTypeInfo) { ClassTypeInfo classContext = (ClassTypeInfo)context; for (TypeInfo implementedInterface : classContext.getInterfaces()) { TypeInfo resolvedType = resolve(implementedInterface, typeVariable); if (!resolvedType.equals(typeVariable)) { return resolvedType; } } TypeInfo superClass = classContext.getSuperType(); if (superClass != null) { return resolve(superClass, typeVariable); } else { return typeVariable; } } else { throw new UnsupportedOperationException(); } } }