import java.util.WeakHashMap;
import org.aspectj.asm.IHierarchy;
-import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
/** The heart of the world, a map from type signatures to resolved types */
protected TypeMap typeMap = new TypeMap(); // Signature to ResolvedType
+
/** Calculator for working out aspect precedence */
private AspectPrecedenceCalculator precedenceCalculator;
}
public void validateType(UnresolvedType type) { }
+
+ // --- with java5 we can get into a recursive mess if we aren't careful when resolving types (*cough* java.lang.Enum) ---
+
+ // --- this first map is for java15 delegates which may try and recursively access the same type variables.
+ // --- I would rather stash this against a reference type - but we don't guarantee referencetypes are unique for
+ // so we can't :(
+ private Map workInProgress1 = new HashMap();
+ public TypeVariable[] getTypeVariablesCurrentlyBeingProcessed(Class baseClass) {
+ return (TypeVariable[])workInProgress1.get(baseClass);
+ }
+ public void recordTypeVariablesCurrentlyBeingProcessed(Class baseClass, TypeVariable[] typeVariables) {
+ workInProgress1.put(baseClass,typeVariables);
+ }
+ public void forgetTypeVariablesCurrentlyBeingProcessed(Class baseClass) {
+ workInProgress1.remove(baseClass);
+ }
+
+ // ---
}
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjType;
return superclass;
}
+
public TypeVariable[] getTypeVariables() {
+ TypeVariable[] workInProgressSetOfVariables = (TypeVariable[])getResolvedTypeX().getWorld().getTypeVariablesCurrentlyBeingProcessed(getBaseClass());
+ if (workInProgressSetOfVariables!=null) {
+ return workInProgressSetOfVariables;
+ }
if (this.typeVariables == null) {
java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters();
this.typeVariables = new TypeVariable[tVars.length];
+ // basic initialization
+ for (int i = 0; i < tVars.length; i++) {
+ typeVariables[i] = new TypeVariable(tVars[i].getName());
+ }
+ // stash it
+ this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(),typeVariables);
+ // now fill in the details...
for (int i = 0; i < tVars.length; i++) {
- this.typeVariables[i] = ((TypeVariableReferenceType) fromType(tVars[i])).getTypeVariable();
+ TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) fromType(tVars[i]));
+ TypeVariable tv = tvrt.getTypeVariable();
+ typeVariables[i].setUpperBound(tv.getUpperBound());
+ typeVariables[i].setAdditionalInterfaceBounds(tv.getAdditionalInterfaceBounds());
+ typeVariables[i].setDeclaringElement(tv.getDeclaringElement());
+ typeVariables[i].setDeclaringElementKind(tv.getDeclaringElementKind());
+ typeVariables[i].setRank(tv.getRank());
+ typeVariables[i].setLowerBound(tv.getLowerBound());
}
+ this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass());
}
return this.typeVariables;
}
return methods;
}
+ /**
+ * Returns the generic type, regardless of the resolvedType we 'know about'
+ */
+ public ResolvedType getGenericResolvedType() {
+ ResolvedType rt = getResolvedTypeX();
+ if (rt.isParameterizedType() || rt.isRawType()) return rt.getGenericType();
+ return rt;
+ }
+
private ResolvedMember createGenericMethodMember(Method forMethod) {
ReflectionBasedResolvedMemberImpl ret =
new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD,
- getResolvedTypeX(),
+ getGenericResolvedType(),
forMethod.getModifiers(),
fromType(forMethod.getGenericReturnType()),
forMethod.getName(),
private ResolvedMember createGenericConstructorMember(Constructor forConstructor) {
ReflectionBasedResolvedMemberImpl ret =
new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD,
- getResolvedTypeX(),
+ getGenericResolvedType(),
forConstructor.getModifiers(),
- getResolvedTypeX(),
+ getGenericResolvedType(),
"init",
fromTypes(forConstructor.getGenericParameterTypes()),
fromTypes(forConstructor.getGenericExceptionTypes()),
ReflectionBasedResolvedMemberImpl ret =
new ReflectionBasedResolvedMemberImpl(
org.aspectj.weaver.Member.FIELD,
- getResolvedTypeX(),
+ getGenericResolvedType(),
forField.getModifiers(),
fromType(forField.getGenericType()),
forField.getName(),
return getBaseClass().getTypeParameters().length > 0;
}
+ // Used to prevent recursion - we record what we are working on and return it if asked again *whilst* working on it
+ private Map /*java.lang.reflect.TypeVariable > TypeVariableReferenceType */typeVariablesInProgress = new HashMap();
+
private ResolvedType fromType(Type aType) {
if (aType instanceof Class) {
Class clazz = (Class)aType;
ResolvedType[] resolvedArgs = fromTypes(args);
return TypeFactory.createParameterizedType(baseType, resolvedArgs, getWorld());
} else if (aType instanceof java.lang.reflect.TypeVariable) {
+ if (typeVariablesInProgress.get(aType)!=null) // check if we are already working on this type
+ return (TypeVariableReferenceType)typeVariablesInProgress.get(aType);
+
java.lang.reflect.TypeVariable tv = (java.lang.reflect.TypeVariable) aType;
+ TypeVariable rt_tv = new TypeVariable(tv.getName());
+ TypeVariableReferenceType tvrt = new TypeVariableReferenceType(rt_tv,getWorld());
+
+ typeVariablesInProgress.put(aType,tvrt); // record what we are working on, for recursion case
+
Type[] bounds = tv.getBounds();
ResolvedType[] resBounds = fromTypes(bounds);
ResolvedType upperBound = resBounds[0];
additionalBounds = new ResolvedType[resBounds.length - 1];
System.arraycopy(resBounds,1,additionalBounds,0,additionalBounds.length);
}
- TypeVariable rt_tv = new TypeVariable(tv.getName(),upperBound,additionalBounds);
- return new TypeVariableReferenceType(rt_tv,getWorld());
+ rt_tv.setUpperBound(upperBound);
+ rt_tv.setAdditionalInterfaceBounds(additionalBounds);
+
+ typeVariablesInProgress.remove(aType); // we have finished working on it
+
+ return tvrt;
} else if (aType instanceof WildcardType) {
WildcardType wildType = (WildcardType) aType;
Type[] lowerBounds = wildType.getLowerBounds();
} else if (aType instanceof GenericArrayType) {
GenericArrayType gt = (GenericArrayType) aType;
Type componentType = gt.getGenericComponentType();
- UnresolvedType.makeArray(fromType(componentType),1);
+ return UnresolvedType.makeArray(fromType(componentType),1).resolve(getWorld());
}
return ResolvedType.MISSING;
}
public class TestJava5ReflectionBasedReferenceTypeDelegate extends ReflectionBasedReferenceTypeDelegateTest {
+ /**
+ * Let's play about with a generic type and ensure we can work with it in a reflective world.
+ */
public void testResolveGeneric() {
- UnresolvedType collectionType = UnresolvedType.forName("java.util.Collection<E>");
-// ResolvedType rt= world.resolve(collectionType);
-// ResolvedMember[] methods = world.resolve(collectionType).getDeclaredMethods();
-// assertTrue(findMethod("toArray", methods) != -1);
+ UnresolvedType collectionType = UnresolvedType.forName("java.util.Collection");
+ ResolvedType rt= world.resolve(collectionType).getRawType().resolve(world);
+ ResolvedMember[] methods = world.resolve(collectionType).getDeclaredMethods();
+ int i = findMethod("toArray", methods);
+ assertTrue("Couldn't find 'toArray' in the set of methods? "+methods,i != -1);
+ String expectedSignature = "T[] java.util.Collection.toArray(T[])";
+ assertTrue("Expected signature of '"+expectedSignature+"' but it was '"+methods[i],methods[i].toString().equals(expectedSignature));
+ }
+
+ /**
+ * Can we resolve the dreaded Enum type...
+ */
+ public void testResolveEnum() {
+ ResolvedType enumType = world.resolve("java.lang.Enum");
+ assertTrue("Should be the raw type but is "+enumType.typeKind,enumType.isRawType());
+ ResolvedType theGenericEnumType = enumType.getGenericType();
+ assertTrue("Should have a type variable ",theGenericEnumType.getTypeVariables().length>0);
+ TypeVariable tv = theGenericEnumType.getTypeVariables()[0];
+ String expected = "TypeVar E extends java.lang.Enum<E>";
+ assertTrue("Type variable should be '"+expected+"' but is '"+tv+"'",tv.toString().equals(expected));
}
public void testResolveClass() {
- //stack overflow
- world.resolve("java.lang.Class");
+ world.resolve("java.lang.Class").getGenericType();
}
- // just here to override the super one so it doesnt run in this case ;)
- public void testGetDeclaredMethods() {
-
- }
-
-
+
}