package org.androidtransfuse.adapter; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author John Ericksen */ public final class GenericsUtil { private static class TypeArgument{ ASTType type; ASTGenericArgument argument; public TypeArgument(ASTType type, ASTGenericArgument argument) { this.type = type; this.argument = argument; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof TypeArgument)) return false; TypeArgument that = (TypeArgument) o; return new EqualsBuilder() .append(type, that.type) .append(argument, that.argument) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder(17, 37) .append(type) .append(argument) .toHashCode(); } @Override public String toString() { return "(" + type.getPackageClass().getClassName() + " " + argument + ")"; } } private static final GenericsUtil INSTANCE = new GenericsUtil(); private GenericsUtil() {} public static GenericsUtil getInstance() { return INSTANCE; } public ASTType getType(ASTType rootType, ASTType containingType, ASTType targetGenericType) { if (targetGenericType instanceof ASTGenericParameterType) { return getType(rootType, containingType, ((ASTGenericParameterType)targetGenericType).getArgument()); } return targetGenericType; } public ASTType getType(ASTType rootType, ASTType containingType, ASTGenericArgument targetGenericType) { Map<TypeArgument, TypeArgument> implementations = new HashMap<TypeArgument, TypeArgument>(); Map<TypeArgument, ASTType> concretes = new HashMap<TypeArgument, ASTType>(); recursivePopulate(implementations, concretes, null, rootType); return recursiveFindType(implementations, concretes, new TypeArgument(containingType, targetGenericType)); } private void recursivePopulate(Map<TypeArgument, TypeArgument> implementations, Map<TypeArgument, ASTType> concretes, ASTType implementationType, ASTType declaredType) { if(implementationType != null) { for (int i = 0; i < declaredType.getGenericArgumentTypes().size(); i++) { ASTType genericArgumentType = declaredType.getGenericArgumentTypes().get(i); TypeArgument genericArgument = new TypeArgument(declaredType, declaredType.getGenericArguments().get(i)); if (genericArgumentType instanceof ASTGenericParameterType) { implementations.put(genericArgument, new TypeArgument(implementationType, ((ASTGenericParameterType) genericArgumentType).getArgument())); } else { concretes.put(genericArgument, genericArgumentType); } } } if (declaredType.getSuperClass() != null) { recursivePopulate(implementations, concretes, declaredType, declaredType.getSuperClass()); Set<ASTType> genericInterfaces = declaredType.getInterfaces(); for (ASTType genericInterface : genericInterfaces) { recursivePopulate(implementations, concretes, declaredType, genericInterface); } } } private ASTType recursiveFindType(Map<TypeArgument, TypeArgument> implementations, Map<TypeArgument, ASTType> concretes, TypeArgument targetArgument) { if (concretes.containsKey(targetArgument)) { return concretes.get(targetArgument); } if (implementations.containsKey(targetArgument)) { return recursiveFindType(implementations, concretes, implementations.get(targetArgument)); } return null; } }