| /* ******************************************************************* |
| * Copyright (c) 2005 Contributors. |
| * All rights reserved. |
| * This program and the accompanying materials are made available |
| * under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution and is available at |
| * http://eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Adrian Colyer Initial implementation |
| * ******************************************************************/ |
| package org.aspectj.weaver.reflect; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Type; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.aspectj.lang.annotation.Aspect; |
| import org.aspectj.lang.reflect.AjType; |
| import org.aspectj.lang.reflect.AjTypeSystem; |
| import org.aspectj.lang.reflect.Pointcut; |
| import org.aspectj.weaver.AnnotationAJ; |
| import org.aspectj.weaver.ReferenceType; |
| import org.aspectj.weaver.ResolvedMember; |
| import org.aspectj.weaver.ResolvedPointcutDefinition; |
| import org.aspectj.weaver.ResolvedType; |
| import org.aspectj.weaver.TypeVariable; |
| import org.aspectj.weaver.TypeVariableReferenceType; |
| import org.aspectj.weaver.UnresolvedType; |
| import org.aspectj.weaver.World; |
| import org.aspectj.weaver.tools.PointcutDesignatorHandler; |
| import org.aspectj.weaver.tools.PointcutParameter; |
| |
| /** |
| * Provides Java 5 behaviour in reflection based delegates (overriding 1.4 behaviour from superclass where |
| * appropriate) |
| * |
| * @author Adrian Colyer |
| * @author Andy Clement |
| */ |
| public class Java15ReflectionBasedReferenceTypeDelegate extends ReflectionBasedReferenceTypeDelegate { |
| |
| private AjType<?> myType; |
| private ResolvedType[] annotations; |
| private ResolvedMember[] pointcuts; |
| private ResolvedMember[] methods; |
| private ResolvedMember[] fields; |
| private TypeVariable[] typeVariables; |
| private ResolvedType superclass; |
| private ResolvedType[] superInterfaces; |
| private String genericSignature = null; |
| private JavaLangTypeToResolvedTypeConverter typeConverter; |
| private Java15AnnotationFinder annotationFinder = null; |
| private ArgNameFinder argNameFinder = null; |
| |
| public Java15ReflectionBasedReferenceTypeDelegate() { |
| } |
| |
| @Override |
| public void initialize(ReferenceType aType, Class aClass, ClassLoader classLoader, World aWorld) { |
| super.initialize(aType, aClass, classLoader, aWorld); |
| myType = AjTypeSystem.getAjType(aClass); |
| annotationFinder = new Java15AnnotationFinder(); |
| argNameFinder = annotationFinder; |
| annotationFinder.setClassLoader(this.classLoaderReference.getClassLoader()); |
| annotationFinder.setWorld(aWorld); |
| this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld); |
| } |
| |
| @Override |
| public ReferenceType buildGenericType() { |
| return (ReferenceType) UnresolvedType.forGenericTypeVariables(getResolvedTypeX().getSignature(), getTypeVariables()) |
| .resolve(getWorld()); |
| } |
| |
| @Override |
| public AnnotationAJ[] getAnnotations() { |
| // AMC - we seem not to need to implement this method... |
| // throw new UnsupportedOperationException( |
| // "getAnnotations on Java15ReflectionBasedReferenceTypeDelegate is not implemented yet" |
| // ); |
| // FIXME is this the right implementation in the reflective case? |
| return super.getAnnotations(); |
| } |
| |
| @Override |
| public ResolvedType[] getAnnotationTypes() { |
| if (annotations == null) { |
| annotations = annotationFinder.getAnnotations(getBaseClass(), getWorld()); |
| } |
| return annotations; |
| } |
| |
| @Override |
| public boolean hasAnnotations() { |
| if (annotations == null) { |
| annotations = annotationFinder.getAnnotations(getBaseClass(), getWorld()); |
| } |
| return annotations.length != 0; |
| } |
| |
| @Override |
| public boolean hasAnnotation(UnresolvedType ofType) { |
| ResolvedType[] myAnns = getAnnotationTypes(); |
| ResolvedType toLookFor = ofType.resolve(getWorld()); |
| for (int i = 0; i < myAnns.length; i++) { |
| if (myAnns[i] == toLookFor) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // use the MAP to ensure that any aj-synthetic fields are filtered out |
| @Override |
| public ResolvedMember[] getDeclaredFields() { |
| if (fields == null) { |
| Field[] reflectFields = this.myType.getDeclaredFields(); |
| ResolvedMember[] rFields = new ResolvedMember[reflectFields.length]; |
| for (int i = 0; i < reflectFields.length; i++) { |
| rFields[i] = createGenericFieldMember(reflectFields[i]); |
| } |
| this.fields = rFields; |
| } |
| return fields; |
| } |
| |
| @Override |
| public String getDeclaredGenericSignature() { |
| if (this.genericSignature == null && isGeneric()) { |
| // BUG? what the hell is this doing - see testcode in MemberTestCase15.testMemberSignatureCreation() and run it |
| // off a Reflection World |
| } |
| return genericSignature; |
| } |
| |
| @Override |
| public ResolvedType[] getDeclaredInterfaces() { |
| if (superInterfaces == null) { |
| Type[] genericInterfaces = getBaseClass().getGenericInterfaces(); |
| this.superInterfaces = typeConverter.fromTypes(genericInterfaces); |
| } |
| return superInterfaces; |
| } |
| |
| @Override |
| public ResolvedType getSuperclass() { |
| // Superclass of object is null |
| if (superclass == null && getBaseClass() != Object.class) { |
| Type t = this.getBaseClass().getGenericSuperclass(); |
| if (t != null) { |
| superclass = typeConverter.fromType(t); |
| } |
| if (t == null) { |
| // If the superclass is null, return Object - same as bcel does |
| superclass = getWorld().resolve(UnresolvedType.OBJECT); |
| } |
| } |
| return superclass; |
| } |
| |
| @Override |
| public TypeVariable[] getTypeVariables() { |
| TypeVariable[] workInProgressSetOfVariables = getResolvedTypeX().getWorld().getTypeVariablesCurrentlyBeingProcessed( |
| getBaseClass()); |
| if (workInProgressSetOfVariables != null) { |
| return workInProgressSetOfVariables; |
| } |
| if (this.typeVariables == null) { |
| java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters(); |
| TypeVariable[] rTypeVariables = new TypeVariable[tVars.length]; |
| // basic initialization |
| for (int i = 0; i < tVars.length; i++) { |
| rTypeVariables[i] = new TypeVariable(tVars[i].getName()); |
| } |
| // stash it |
| this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(), rTypeVariables); |
| // now fill in the details... |
| for (int i = 0; i < tVars.length; i++) { |
| TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) typeConverter.fromType(tVars[i])); |
| TypeVariable tv = tvrt.getTypeVariable(); |
| rTypeVariables[i].setSuperclass(tv.getSuperclass()); |
| rTypeVariables[i].setAdditionalInterfaceBounds(tv.getSuperInterfaces()); |
| rTypeVariables[i].setDeclaringElement(tv.getDeclaringElement()); |
| rTypeVariables[i].setDeclaringElementKind(tv.getDeclaringElementKind()); |
| rTypeVariables[i].setRank(tv.getRank()); |
| } |
| this.typeVariables = rTypeVariables; |
| this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass()); |
| } |
| return this.typeVariables; |
| } |
| |
| // overrides super method since by using the MAP we can filter out advice |
| // methods that really shouldn't be seen in this list |
| @Override |
| public ResolvedMember[] getDeclaredMethods() { |
| if (methods == null) { |
| Method[] reflectMethods = this.myType.getDeclaredMethods(); |
| Constructor[] reflectCons = this.myType.getDeclaredConstructors(); |
| ResolvedMember[] rMethods = new ResolvedMember[reflectMethods.length + reflectCons.length]; |
| for (int i = 0; i < reflectMethods.length; i++) { |
| rMethods[i] = createGenericMethodMember(reflectMethods[i]); |
| } |
| for (int i = 0; i < reflectCons.length; i++) { |
| rMethods[i + reflectMethods.length] = createGenericConstructorMember(reflectCons[i]); |
| } |
| this.methods = rMethods; |
| } |
| 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, |
| getGenericResolvedType(), forMethod.getModifiers(), typeConverter.fromType(forMethod.getReturnType()), |
| forMethod.getName(), typeConverter.fromTypes(forMethod.getParameterTypes()), typeConverter.fromTypes(forMethod |
| .getExceptionTypes()), forMethod); |
| ret.setAnnotationFinder(this.annotationFinder); |
| ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld())); |
| return ret; |
| } |
| |
| private ResolvedMember createGenericConstructorMember(Constructor forConstructor) { |
| ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD, |
| getGenericResolvedType(), forConstructor.getModifiers(), |
| // to return what BCEL returns the return type is void |
| UnresolvedType.VOID,// getGenericResolvedType(), |
| "<init>", typeConverter.fromTypes(forConstructor.getParameterTypes()), typeConverter.fromTypes(forConstructor |
| .getExceptionTypes()), forConstructor); |
| ret.setAnnotationFinder(this.annotationFinder); |
| ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld())); |
| return ret; |
| } |
| |
| private ResolvedMember createGenericFieldMember(Field forField) { |
| ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.FIELD, |
| getGenericResolvedType(), forField.getModifiers(), typeConverter.fromType(forField.getType()), forField.getName(), |
| new UnresolvedType[0], forField); |
| ret.setAnnotationFinder(this.annotationFinder); |
| ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld())); |
| return ret; |
| } |
| |
| @Override |
| public ResolvedMember[] getDeclaredPointcuts() { |
| if (pointcuts == null) { |
| Pointcut[] pcs = this.myType.getDeclaredPointcuts(); |
| pointcuts = new ResolvedMember[pcs.length]; |
| InternalUseOnlyPointcutParser parser = null; |
| World world = getWorld(); |
| if (world instanceof ReflectionWorld) { |
| parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader(), (ReflectionWorld) getWorld()); |
| } else { |
| parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader()); |
| } |
| Set additionalPointcutHandlers = world.getRegisteredPointcutHandlers(); |
| for (Iterator handlerIterator = additionalPointcutHandlers.iterator(); handlerIterator.hasNext();) { |
| PointcutDesignatorHandler handler = (PointcutDesignatorHandler) handlerIterator.next(); |
| parser.registerPointcutDesignatorHandler(handler); |
| } |
| |
| // phase 1, create legitimate entries in pointcuts[] before we |
| // attempt to resolve *any* of the pointcuts |
| // resolution can sometimes cause us to recurse, and this two stage |
| // process allows us to cope with that |
| for (int i = 0; i < pcs.length; i++) { |
| AjType<?>[] ptypes = pcs[i].getParameterTypes(); |
| UnresolvedType[] weaverPTypes = new UnresolvedType[ptypes.length]; |
| for (int j = 0; j < weaverPTypes.length; j++) { |
| weaverPTypes[j] = this.typeConverter.fromType(ptypes[j].getJavaClass()); |
| } |
| pointcuts[i] = new DeferredResolvedPointcutDefinition(getResolvedTypeX(), pcs[i].getModifiers(), pcs[i].getName(), |
| weaverPTypes); |
| } |
| // phase 2, now go back round and resolve in-place all of the |
| // pointcuts |
| PointcutParameter[][] parameters = new PointcutParameter[pcs.length][]; |
| for (int i = 0; i < pcs.length; i++) { |
| AjType<?>[] ptypes = pcs[i].getParameterTypes(); |
| String[] pnames = pcs[i].getParameterNames(); |
| if (pnames.length != ptypes.length) { |
| pnames = tryToDiscoverParameterNames(pcs[i]); |
| if (pnames == null || (pnames.length != ptypes.length)) { |
| throw new IllegalStateException("Required parameter names not available when parsing pointcut " |
| + pcs[i].getName() + " in type " + getResolvedTypeX().getName()); |
| } |
| } |
| parameters[i] = new PointcutParameter[ptypes.length]; |
| for (int j = 0; j < parameters[i].length; j++) { |
| parameters[i][j] = parser.createPointcutParameter(pnames[j], ptypes[j].getJavaClass()); |
| } |
| String pcExpr = pcs[i].getPointcutExpression().toString(); |
| org.aspectj.weaver.patterns.Pointcut pc = parser.resolvePointcutExpression(pcExpr, getBaseClass(), parameters[i]); |
| ((ResolvedPointcutDefinition) pointcuts[i]).setParameterNames(pnames); |
| ((ResolvedPointcutDefinition) pointcuts[i]).setPointcut(pc); |
| } |
| // phase 3, now concretize them all |
| for (int i = 0; i < pointcuts.length; i++) { |
| ResolvedPointcutDefinition rpd = (ResolvedPointcutDefinition) pointcuts[i]; |
| rpd.setPointcut(parser.concretizePointcutExpression(rpd.getPointcut(), getBaseClass(), parameters[i])); |
| } |
| } |
| return pointcuts; |
| } |
| |
| // for @AspectJ pointcuts compiled by javac only... |
| private String[] tryToDiscoverParameterNames(Pointcut pcut) { |
| Method[] ms = pcut.getDeclaringType().getJavaClass().getDeclaredMethods(); |
| for (Method m : ms) { |
| if (m.getName().equals(pcut.getName())) { |
| return argNameFinder.getParameterNames(m); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean isAnnotation() { |
| return getBaseClass().isAnnotation(); |
| } |
| |
| @Override |
| public boolean isAnnotationStyleAspect() { |
| return getBaseClass().isAnnotationPresent(Aspect.class); |
| } |
| |
| @Override |
| public boolean isAnnotationWithRuntimeRetention() { |
| if (!isAnnotation()) { |
| return false; |
| } |
| if (getBaseClass().isAnnotationPresent(Retention.class)) { |
| Retention retention = (Retention) getBaseClass().getAnnotation(Retention.class); |
| RetentionPolicy policy = retention.value(); |
| return policy == RetentionPolicy.RUNTIME; |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean isAspect() { |
| return this.myType.isAspect(); |
| } |
| |
| @Override |
| public boolean isEnum() { |
| return getBaseClass().isEnum(); |
| } |
| |
| @Override |
| public boolean isGeneric() { |
| // return false; // for now |
| return getBaseClass().getTypeParameters().length > 0; |
| } |
| |
| @Override |
| public boolean isAnonymous() { |
| return this.myClass.isAnonymousClass(); |
| } |
| |
| @Override |
| public boolean isNested() { |
| return this.myClass.isMemberClass(); |
| } |
| |
| @Override |
| public ResolvedType getOuterClass() { |
| return ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld( |
| myClass.getEnclosingClass(),world); |
| } |
| |
| } |