import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.Set; | import java.util.Set; | ||||
import org.aspectj.apache.bcel.classfile.AnnotationDefault; | |||||
import org.aspectj.apache.bcel.classfile.Attribute; | |||||
import org.aspectj.apache.bcel.classfile.JavaClass; | import org.aspectj.apache.bcel.classfile.JavaClass; | ||||
import org.aspectj.apache.bcel.classfile.LocalVariable; | import org.aspectj.apache.bcel.classfile.LocalVariable; | ||||
import org.aspectj.apache.bcel.classfile.LocalVariableTable; | import org.aspectj.apache.bcel.classfile.LocalVariableTable; | ||||
import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository; | import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository; | ||||
import org.aspectj.apache.bcel.util.Repository; | import org.aspectj.apache.bcel.util.Repository; | ||||
import org.aspectj.weaver.AnnotationX; | |||||
import org.aspectj.weaver.ResolvedType; | import org.aspectj.weaver.ResolvedType; | ||||
import org.aspectj.weaver.UnresolvedType; | import org.aspectj.weaver.UnresolvedType; | ||||
import org.aspectj.weaver.World; | import org.aspectj.weaver.World; | ||||
return null; | return null; | ||||
} | } | ||||
public AnnotationX getAnnotationOfType(UnresolvedType ofType,Member onMember) { | |||||
if (!(onMember instanceof AccessibleObject)) return null; | |||||
// here we really want both the runtime visible AND the class visible annotations | |||||
// so we bail out to Bcel and then chuck away the JavaClass so that we don't hog | |||||
// memory. | |||||
try { | |||||
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); | |||||
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0]; | |||||
if (onMember instanceof Method) { | |||||
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); | |||||
if (bcelMethod == null) { | |||||
// pr220430 | |||||
//System.err.println("Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"+onMember.getName()+"' in class '"+jc.getClassName()+"'"); | |||||
} else { | |||||
anns = bcelMethod.getAnnotations(); | |||||
} | |||||
} else if (onMember instanceof Constructor) { | |||||
org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor)onMember); | |||||
anns = bcelCons.getAnnotations(); | |||||
} else if (onMember instanceof Field) { | |||||
org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field)onMember); | |||||
anns = bcelField.getAnnotations(); | |||||
} | |||||
// the answer is cached and we don't want to hold on to memory | |||||
bcelRepository.clear(); | |||||
if (anns == null) anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0]; | |||||
// convert to our Annotation type | |||||
for (int i=0;i<anns.length;i++) { | |||||
if (anns[i].getTypeSignature().equals(ofType.getSignature())) { | |||||
return new AnnotationX(anns[i],world); | |||||
} | |||||
} | |||||
return null; | |||||
} catch (ClassNotFoundException cnfEx) { | |||||
// just use reflection then | |||||
} | |||||
return null; | |||||
} | |||||
public String getAnnotationDefaultValue(Member onMember) { | |||||
try { | |||||
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); | |||||
if (onMember instanceof Method) { | |||||
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); | |||||
if (bcelMethod == null) { | |||||
// pr220430 | |||||
// System.err.println("Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"+onMember.getName()+"' in class '"+jc.getClassName()+"'"); | |||||
} else { | |||||
Attribute[] attrs = bcelMethod.getAttributes(); | |||||
for (int i = 0; i < attrs.length; i++) { | |||||
Attribute attribute = attrs[i]; | |||||
if (attribute.getName().equals("AnnotationDefault")) { | |||||
AnnotationDefault def = (AnnotationDefault)attribute; | |||||
return def.getElementValue().stringifyValue(); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} catch (ClassNotFoundException cnfEx) { | |||||
// just use reflection then | |||||
} | |||||
return null; | |||||
} | |||||
public Set getAnnotations(Member onMember) { | public Set getAnnotations(Member onMember) { | ||||
if (!(onMember instanceof AccessibleObject)) return Collections.EMPTY_SET; | if (!(onMember instanceof AccessibleObject)) return Collections.EMPTY_SET; | ||||
// here we really want both the runtime visible AND the class visible annotations | // here we really want both the runtime visible AND the class visible annotations | ||||
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0]; | org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0]; | ||||
if (onMember instanceof Method) { | if (onMember instanceof Method) { | ||||
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); | org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); | ||||
anns = bcelMethod.getAnnotations(); | |||||
if (bcelMethod == null) { | |||||
// fallback on reflection - see pr220430 | |||||
// System.err.println("Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"+onMember.getName()+"' in class '"+jc.getClassName()+"'"); | |||||
} else { | |||||
anns = bcelMethod.getAnnotations(); | |||||
} | |||||
} else if (onMember instanceof Constructor) { | } else if (onMember instanceof Constructor) { | ||||
org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor)onMember); | org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor)onMember); | ||||
anns = bcelCons.getAnnotations(); | anns = bcelCons.getAnnotations(); | ||||
} | } | ||||
private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) { | private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) { | ||||
if (lvt == null) | |||||
return null;// pr222987 - prevent NPE | |||||
LocalVariable[] vars = lvt.getLocalVariableTable(); | LocalVariable[] vars = lvt.getLocalVariableTable(); | ||||
if (vars.length < numVars) { | if (vars.length < numVars) { | ||||
// basic error, we can't get the names... | // basic error, we can't get the names... | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
public static final ResolvedType[][] NO_PARAMETER_ANNOTATIONS = new ResolvedType[][]{}; | |||||
public ResolvedType[][] getParameterAnnotationTypes(Member onMember) { | |||||
if (!(onMember instanceof AccessibleObject)) return NO_PARAMETER_ANNOTATIONS; | |||||
// here we really want both the runtime visible AND the class visible annotations | |||||
// so we bail out to Bcel and then chuck away the JavaClass so that we don't hog | |||||
// memory. | |||||
try { | |||||
JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); | |||||
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null; | |||||
if (onMember instanceof Method) { | |||||
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); | |||||
if (bcelMethod == null) { | |||||
// pr220430 | |||||
//System.err.println("Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"+onMember.getName()+"' in class '"+jc.getClassName()+"'"); | |||||
} else { | |||||
anns = bcelMethod.getParameterAnnotations(); | |||||
} | |||||
} else if (onMember instanceof Constructor) { | |||||
org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor)onMember); | |||||
anns = bcelCons.getParameterAnnotations(); | |||||
} else if (onMember instanceof Field) { | |||||
anns = null; | |||||
} | |||||
// the answer is cached and we don't want to hold on to memory | |||||
bcelRepository.clear(); | |||||
if (anns == null) return NO_PARAMETER_ANNOTATIONS; | |||||
ResolvedType[][] result = new ResolvedType[anns.length][]; | |||||
// CACHING?? | |||||
for (int i=0;i<anns.length;i++) { | |||||
if (anns[i]!=null) { | |||||
result[i] = new ResolvedType[anns[i].length]; | |||||
for (int j=0;j<anns[i].length;j++) { | |||||
result[i][j] = world.resolve(UnresolvedType.forSignature(anns[i][j].getTypeSignature())); | |||||
} | |||||
} | |||||
} | |||||
return result; | |||||
} catch (ClassNotFoundException cnfEx) { | |||||
// just use reflection then | |||||
} | |||||
// reflection... | |||||
AccessibleObject ao = (AccessibleObject) onMember; | |||||
Annotation[][] anns = null; | |||||
if (onMember instanceof Method) { | |||||
anns = ((Method)ao).getParameterAnnotations(); | |||||
} else if (onMember instanceof Constructor) { | |||||
anns = ((Constructor)ao).getParameterAnnotations(); | |||||
} else if (onMember instanceof Field) { | |||||
anns = null; | |||||
} | |||||
if (anns == null) return NO_PARAMETER_ANNOTATIONS; | |||||
ResolvedType[][] result = new ResolvedType[anns.length][]; | |||||
// CACHING?? | |||||
for (int i=0;i<anns.length;i++) { | |||||
if (anns[i]!=null) { | |||||
result[i] = new ResolvedType[anns[i].length]; | |||||
for (int j=0;j<anns[i].length;j++) { | |||||
result[i][j] = UnresolvedType.forName(anns[i][j].annotationType().getName()).resolve(world); | |||||
} | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
} | } |
import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||
import java.util.Iterator; | |||||
import java.util.Set; | |||||
import org.aspectj.lang.annotation.Aspect; | import org.aspectj.lang.annotation.Aspect; | ||||
import org.aspectj.lang.reflect.AjType; | import org.aspectj.lang.reflect.AjType; | ||||
import org.aspectj.weaver.TypeVariableReferenceType; | import org.aspectj.weaver.TypeVariableReferenceType; | ||||
import org.aspectj.weaver.UnresolvedType; | import org.aspectj.weaver.UnresolvedType; | ||||
import org.aspectj.weaver.World; | import org.aspectj.weaver.World; | ||||
import org.aspectj.weaver.tools.PointcutDesignatorHandler; | |||||
import org.aspectj.weaver.tools.PointcutParameter; | import org.aspectj.weaver.tools.PointcutParameter; | ||||
/** | /** | ||||
annotationFinder = new Java15AnnotationFinder(); | annotationFinder = new Java15AnnotationFinder(); | ||||
argNameFinder = annotationFinder; | argNameFinder = annotationFinder; | ||||
annotationFinder.setClassLoader(this.classLoader); | annotationFinder.setClassLoader(this.classLoader); | ||||
annotationFinder.setWorld(aWorld); | |||||
this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld); | this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld); | ||||
} | } | ||||
public ResolvedMember[] getDeclaredFields() { | public ResolvedMember[] getDeclaredFields() { | ||||
if (fields == null) { | if (fields == null) { | ||||
Field[] reflectFields = this.myType.getDeclaredFields(); | Field[] reflectFields = this.myType.getDeclaredFields(); | ||||
this.fields = new ResolvedMember[reflectFields.length]; | |||||
ResolvedMember[] rFields = new ResolvedMember[reflectFields.length]; | |||||
for (int i = 0; i < reflectFields.length; i++) { | for (int i = 0; i < reflectFields.length; i++) { | ||||
this.fields[i] = createGenericFieldMember(reflectFields[i]); | |||||
rFields[i] = createGenericFieldMember(reflectFields[i]); | |||||
} | } | ||||
this.fields = rFields; | |||||
} | } | ||||
return fields; | return fields; | ||||
} | } | ||||
} | } | ||||
if (this.typeVariables == null) { | if (this.typeVariables == null) { | ||||
java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters(); | java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters(); | ||||
this.typeVariables = new TypeVariable[tVars.length]; | |||||
TypeVariable[] rTypeVariables = new TypeVariable[tVars.length]; | |||||
// basic initialization | // basic initialization | ||||
for (int i = 0; i < tVars.length; i++) { | for (int i = 0; i < tVars.length; i++) { | ||||
typeVariables[i] = new TypeVariable(tVars[i].getName()); | |||||
rTypeVariables[i] = new TypeVariable(tVars[i].getName()); | |||||
} | } | ||||
// stash it | // stash it | ||||
this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(),typeVariables); | |||||
this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(), rTypeVariables); | |||||
// now fill in the details... | // now fill in the details... | ||||
for (int i = 0; i < tVars.length; i++) { | for (int i = 0; i < tVars.length; i++) { | ||||
TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) typeConverter.fromType(tVars[i])); | TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) typeConverter.fromType(tVars[i])); | ||||
TypeVariable tv = tvrt.getTypeVariable(); | 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()); | |||||
rTypeVariables[i].setUpperBound(tv.getUpperBound()); | |||||
rTypeVariables[i].setAdditionalInterfaceBounds(tv.getAdditionalInterfaceBounds()); | |||||
rTypeVariables[i].setDeclaringElement(tv.getDeclaringElement()); | |||||
rTypeVariables[i].setDeclaringElementKind(tv.getDeclaringElementKind()); | |||||
rTypeVariables[i].setRank(tv.getRank()); | |||||
rTypeVariables[i].setLowerBound(tv.getLowerBound()); | |||||
} | } | ||||
this.typeVariables = rTypeVariables; | |||||
this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass()); | this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass()); | ||||
} | } | ||||
return this.typeVariables; | return this.typeVariables; | ||||
if (methods == null) { | if (methods == null) { | ||||
Method[] reflectMethods = this.myType.getDeclaredMethods(); | Method[] reflectMethods = this.myType.getDeclaredMethods(); | ||||
Constructor[] reflectCons = this.myType.getDeclaredConstructors(); | Constructor[] reflectCons = this.myType.getDeclaredConstructors(); | ||||
this.methods = new ResolvedMember[reflectMethods.length + reflectCons.length]; | |||||
ResolvedMember[] rMethods = new ResolvedMember[reflectMethods.length + reflectCons.length]; | |||||
for (int i = 0; i < reflectMethods.length; i++) { | for (int i = 0; i < reflectMethods.length; i++) { | ||||
this.methods[i] = createGenericMethodMember(reflectMethods[i]); | |||||
rMethods[i] = createGenericMethodMember(reflectMethods[i]); | |||||
} | } | ||||
for (int i = 0; i < reflectCons.length; i++) { | for (int i = 0; i < reflectCons.length; i++) { | ||||
this.methods[i + reflectMethods.length] = | |||||
rMethods[i + reflectMethods.length] = | |||||
createGenericConstructorMember(reflectCons[i]); | createGenericConstructorMember(reflectCons[i]); | ||||
} | } | ||||
this.methods = rMethods; | |||||
} | } | ||||
return methods; | return methods; | ||||
} | } | ||||
} else { | } else { | ||||
parser = new InternalUseOnlyPointcutParser(classLoader); | parser = new InternalUseOnlyPointcutParser(classLoader); | ||||
} | } | ||||
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 | // 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 | // resolution can sometimes cause us to recurse, and this two stage process allows us to cope with that |
import java.util.logging.Level; | import java.util.logging.Level; | ||||
import java.util.logging.Logger; | import java.util.logging.Logger; | ||||
// OPTIMIZE move out for now? check what doc says about using these variants on trace (commons/14) | |||||
public class Jdk14Trace extends AbstractTrace { | public class Jdk14Trace extends AbstractTrace { | ||||
private Logger logger; | private Logger logger; |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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: | |||||
* Andy Clement initial implementation | |||||
* ******************************************************************/ | |||||
import org.aspectj.lang.annotation.Aspect; | |||||
import org.aspectj.lang.annotation.Before; | |||||
import org.aspectj.lang.annotation.Pointcut; | |||||
/** | |||||
* Created to enable PointcutDesignatorHandlerTests.testParsingBeanInReferencePointcut01 and 02 to run | |||||
* | |||||
* @author Andy Clement | |||||
*/ | |||||
@Aspect | |||||
public class CounterAspect { | |||||
int count; | |||||
@Before("execution(* set*(..)) && bean(testBean1)") | |||||
public void increment1ForAnonymousPointcut() { | |||||
count++; | |||||
} | |||||
@Pointcut("execution(* toString(..)) && bean(testBean1)") | |||||
public void testBean1toString() { | |||||
} | |||||
@Pointcut("execution(* setAge(..)) && bean(testBean1)") | |||||
public void testBean1SetAge() { | |||||
} | |||||
@Pointcut("execution(* setAge(..)) && bean(testBean2)") | |||||
public void testBean2SetAge() { | |||||
} | |||||
@Before("testBean1SetAge()") | |||||
public void increment1() { | |||||
count++; | |||||
} | |||||
@Before("testBean2SetAge()") | |||||
public void increment2() { | |||||
count++; | |||||
} | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
public @interface MA { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
public @interface MB { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
public @interface MC { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
public @interface MD { | |||||
} |
import java.lang.annotation.Retention; | import java.lang.annotation.Retention; | ||||
import java.lang.annotation.RetentionPolicy; | import java.lang.annotation.RetentionPolicy; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.util.ArrayList; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.HashSet; | |||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | |||||
import java.util.StringTokenizer; | |||||
import org.aspectj.lang.annotation.Pointcut; | import org.aspectj.lang.annotation.Pointcut; | ||||
import org.aspectj.weaver.ResolvedType; | |||||
import org.aspectj.weaver.internal.tools.PointcutExpressionImpl; | |||||
import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; | |||||
import org.aspectj.weaver.patterns.AndAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.AnnotationPatternList; | |||||
import org.aspectj.weaver.patterns.AnyAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.BindingAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.ExactAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.KindedPointcut; | |||||
import org.aspectj.weaver.patterns.NotAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.OrAnnotationTypePattern; | |||||
import org.aspectj.weaver.patterns.SignaturePattern; | |||||
import org.aspectj.weaver.patterns.TypePattern; | |||||
import org.aspectj.weaver.patterns.TypePatternList; | |||||
import org.aspectj.weaver.patterns.WildAnnotationTypePattern; | |||||
import test.A1AnnotatedType; | |||||
import test.A2AnnotatedType; | |||||
import junit.framework.Test; | import junit.framework.Test; | ||||
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import junit.framework.TestSuite; | import junit.framework.TestSuite; | ||||
/** | /** | ||||
* @author colyer | |||||
* Test parameter pointcut parsing. Extended by Andy Clement to cover parameter annotation matching. | |||||
* | * | ||||
*/ | */ | ||||
public class Java15PointcutExpressionTest extends TestCase { | public class Java15PointcutExpressionTest extends TestCase { | ||||
private Method c; | private Method c; | ||||
private Method d; | private Method d; | ||||
/** | |||||
* Parse some expressions and ensure we capture the parameter annotations and parameter type annotations correctly. | |||||
* Buckle up, this will get complicated ;) | |||||
*/ | |||||
public void testParseParameterAnnotationExpressions() { | |||||
PointcutParser p = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(this.getClass().getClassLoader()); | |||||
PointcutExpression pexpr = null; | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA *))"); | |||||
checkParameterAnnotations(pexpr,0,null,"@MA","exact[@MA:t]"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA (*)))"); | |||||
checkParameterAnnotations(pexpr,0,"@MA",null,"exact[@MA:p]"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA @MB *))"); | |||||
checkParameterAnnotations(pexpr,0,null,"@MA @MB","(exact[@MA:t] and exact[@MB:t])"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA (@MB *)))"); | |||||
checkParameterAnnotations(pexpr,0,"@MA","@MB","(exact[@MA:p] and exact[@MB:t])"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA @MB (@MC *)))"); | |||||
checkParameterAnnotations(pexpr,0,"@MA @MB","@MC","((exact[@MA:p] and exact[@MB:p]) and exact[@MC:t])"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA (@MB @MC @MD *)))"); | |||||
checkParameterAnnotations(pexpr,0,"@MA","@MB @MC @MD","(exact[@MA:p] and ((exact[@MB:t] and exact[@MC:t]) and exact[@MD:t]))"); | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@(MA || MB) (@MC @MD *)))"); | |||||
checkParameterAnnotations(pexpr,0,null/*Should be MA MB */,"@MC @MD","(wild[(MA || MB)] and (exact[@MC:t] and exact[@MD:t]))"); // I dont think WildAnnotationTypePatterns work properly... | |||||
pexpr = p.parsePointcutExpression("execution(public void foo(@MA (@MB *),(@MC *),@MD (*)))"); | |||||
checkParameterAnnotations(pexpr,0,"@MA","@MB","(exact[@MA:p] and exact[@MB:t])"); | |||||
checkParameterAnnotations(pexpr,1,null,"@MC","exact[@MC:t]"); | |||||
checkParameterAnnotations(pexpr,2,"@MD",null,"exact[@MD:p]"); | |||||
} | |||||
public void testMatchingAnnotationValueExpressions() throws SecurityException, NoSuchMethodException { | |||||
PointcutParser p = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(this.getClass().getClassLoader()); | |||||
PointcutExpression pexpr = null; | |||||
ShadowMatch match = null; | |||||
Method n = test.AnnoValues.class.getMethod("none",null); | |||||
Method r = test.AnnoValues.class.getMethod("redMethod",null); | |||||
Method g = test.AnnoValues.class.getMethod("greenMethod",null); | |||||
Method b = test.AnnoValues.class.getMethod("blueMethod",null); | |||||
Method d = test.AnnoValues.class.getMethod("defaultMethod",null); | |||||
pexpr = p.parsePointcutExpression("execution(@test.A3(test.Color.RED) public void *(..))"); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(n).neverMatches()); // default value RED | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(r).alwaysMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(g).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(b).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(d).alwaysMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(@test.A3(test.Color.GREEN) public void *(..))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(n).neverMatches()); // default value RED | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(r).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(g).alwaysMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(b).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(d).neverMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(@test.A3(test.Color.BLUE) public void *(..))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(n).neverMatches()); // default value RED | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(r).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(g).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(b).alwaysMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(d).neverMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(@test.A3 public void *(..))"); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(n).neverMatches()); // default value RED | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(r).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(g).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(b).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(d).alwaysMatches()); | |||||
} | |||||
/** | |||||
* Test matching of pointcuts against expressions. A reflection world is being used on the backend here (not a Bcel one). | |||||
*/ | |||||
public void testMatchingParameterAnnotationExpressions() throws SecurityException, NoSuchMethodException { | |||||
PointcutParser p = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(this.getClass().getClassLoader()); | |||||
PointcutExpression pexpr = null; | |||||
ShadowMatch match = null; | |||||
Method a = test.A.class.getMethod("a",new Class[] {String.class}); // public void a(String s) {} | |||||
Method b = test.A.class.getMethod("b",new Class[] {String.class}); // public void b(@A1 String s) {} | |||||
Method c = test.A.class.getMethod("c",new Class[] {String.class}); // public void c(@A1 @A2 String s) {} | |||||
Method d = test.A.class.getMethod("d",new Class[] {String.class,String.class});// public void d(@A1 String s,@A2 String t) {} | |||||
Method e = test.A.class.getMethod("e",new Class[] {A1AnnotatedType.class}); // public void e(A1AnnotatedType s) {} | |||||
Method f = test.A.class.getMethod("f",new Class[] {A2AnnotatedType.class}); // public void f(A2AnnotatedType s) {} | |||||
Method g = test.A.class.getMethod("g",new Class[] {A1AnnotatedType.class}); // public void g(@A2 A1AnnotatedType s) {} | |||||
Method h = test.A.class.getMethod("h",new Class[] {A1AnnotatedType.class}); // public void h(@A1 A1AnnotatedType s) {} | |||||
Method i = test.A.class.getMethod("i",new Class[] {A1AnnotatedType.class,String.class}); // public void i(A1AnnotatedType s,@A2 String t) {} | |||||
Method j = test.A.class.getMethod("j",new Class[] {String.class}); // public void j(@A1 @A2 String s) {} | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@test.A1 *))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(a).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(b).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(c).neverMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@test.A1 (*)))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(a).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(b).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(c).alwaysMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@test.A1 *))"); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(e).alwaysMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(f).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(g).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(h).alwaysMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@test.A1 (*)))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(e).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(f).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(g).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(h).alwaysMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@(test.A1 || test.A2) (*)))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(a).neverMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(b).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(c).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(g).alwaysMatches()); | |||||
assertTrue("Should match", pexpr.matchesMethodExecution(h).alwaysMatches()); | |||||
pexpr = p.parsePointcutExpression("execution(public void *(@(test.A1 && test.A2) (*),..))"); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(a).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(b).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(c).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(g).neverMatches()); | |||||
assertTrue("Should not match", pexpr.matchesMethodExecution(h).neverMatches()); | |||||
// assertTrue("Should match", pexpr.matchesMethodExecution(j).alwaysMatches()); // should match but does not, broken implementation, old bug - see WildAnnotationTypePattern.match | |||||
} | |||||
private void checkParameterAnnotations(PointcutExpression pe,int parameterNumber,String expectedParameterAnnotations,String expectedParameterTypeAnnotations,String expectedNodeStructure) { | |||||
org.aspectj.weaver.patterns.Pointcut p = ((PointcutExpressionImpl)pe).getUnderlyingPointcut(); | |||||
KindedPointcut kindedP = (KindedPointcut)p; | |||||
SignaturePattern sp = kindedP.getSignature(); | |||||
TypePatternList tpl = sp.getParameterTypes(); | |||||
TypePattern[] tps = tpl.getTypePatterns(); | |||||
// A visitor over the annotation pattern for the parameter will break it down into parameter vs parameter type annotations | |||||
MyPatternNodeVisitor mpnv = new MyPatternNodeVisitor(); | |||||
tps[parameterNumber].getAnnotationPattern().accept(mpnv,null); | |||||
if (expectedNodeStructure==null) { | |||||
// The caller hasn't worked it out yet!! | |||||
System.out.println(mpnv.getStringRepresentation()); | |||||
} else if (!mpnv.getStringRepresentation().equals(expectedNodeStructure)) { | |||||
System.out.println(mpnv.getStringRepresentation()); | |||||
fail("Expected annotation pattern node structure for expression "+pe.getPointcutExpression()+ | |||||
" was '"+expectedNodeStructure+"' but it turned out to be '"+mpnv.getStringRepresentation()+"'"); | |||||
} | |||||
String annotationTypePattern = tps[parameterNumber].getAnnotationPattern().toString(); | |||||
// parameter type annotation checking | |||||
Set<String> expected = new HashSet<String>(); | |||||
expected.addAll(mpnv.getParameterTypeAnnotations()); | |||||
StringTokenizer st = new StringTokenizer(expectedParameterTypeAnnotations==null?"":expectedParameterTypeAnnotations); | |||||
while (st.hasMoreTokens()) { | |||||
String nextToken = st.nextToken(); | |||||
if (!expected.contains(nextToken)) | |||||
fail("In pointcut expression "+pe.getPointcutExpression()+" parameter "+parameterNumber+". The annotation type pattern did not include parameter type annotation "+nextToken+". It's full set was "+mpnv.getParameterTypeAnnotations()); | |||||
expected.remove(nextToken); | |||||
} | |||||
if (expected.size()>0) { // we have excess ones! | |||||
StringBuffer excessTokens = new StringBuffer(); | |||||
for (Iterator iterator = expected.iterator(); iterator.hasNext();) { | |||||
String string = (String) iterator.next(); | |||||
excessTokens.append(string).append(" "); | |||||
} | |||||
fail("In pointcut expression "+pe.getPointcutExpression()+" parameter "+parameterNumber+". The annotation type pattern has these unexpected parameter type annotations "+excessTokens.toString()); | |||||
} | |||||
// parameter annotation checking | |||||
expected = new HashSet<String>(); | |||||
expected.addAll(mpnv.getParameterAnnotations()); | |||||
st = new StringTokenizer(expectedParameterAnnotations==null?"":expectedParameterAnnotations); | |||||
while (st.hasMoreTokens()) { | |||||
String nextToken = st.nextToken(); | |||||
if (!expected.contains(nextToken)) | |||||
fail("In pointcut expression "+pe.getPointcutExpression()+" parameter "+parameterNumber+". The annotation type pattern did not include parameter annotation "+nextToken+". It's full set was "+mpnv.getParameterAnnotations()); | |||||
expected.remove(nextToken); | |||||
} | |||||
if (expected.size()>0) { // we have excess ones! | |||||
StringBuffer excessTokens = new StringBuffer(); | |||||
for (Iterator iterator = expected.iterator(); iterator.hasNext();) { | |||||
String string = (String) iterator.next(); | |||||
excessTokens.append(string).append(" "); | |||||
} | |||||
fail("In pointcut expression "+pe.getPointcutExpression()+" parameter "+parameterNumber+". The annotation type pattern has these unexpected parameter annotations "+excessTokens.toString()); | |||||
} | |||||
} | |||||
static class MyPatternNodeVisitor extends AbstractPatternNodeVisitor { | |||||
private StringBuffer stringRep = new StringBuffer(); | |||||
private List<String> parameterAnnotations = new ArrayList<String>(); | |||||
private List<String> parameterTypeAnnotations = new ArrayList<String>(); | |||||
public String getStringRepresentation() { return stringRep.toString(); } | |||||
public List<String> getParameterAnnotations() { return parameterAnnotations; } | |||||
public List<String> getParameterTypeAnnotations() { return parameterTypeAnnotations; } | |||||
public Object visit(AndAnnotationTypePattern node, Object data) { | |||||
stringRep.append("("); | |||||
node.getLeft().accept(this, data); | |||||
stringRep.append(" and "); | |||||
node.getRight().accept(this, data); | |||||
stringRep.append(")"); | |||||
return node; | |||||
} | |||||
public Object visit(AnyAnnotationTypePattern node, Object data) { | |||||
stringRep.append("any"); | |||||
return node; | |||||
} | |||||
public Object visit(ExactAnnotationTypePattern node, Object data) { | |||||
stringRep.append("exact["+stringify(node.getResolvedAnnotationType())+":"+(node.isForParameterAnnotationMatch()?"p":"t")+"]"); | |||||
if (node.isForParameterAnnotationMatch()) { | |||||
parameterAnnotations.add(stringify(node.getResolvedAnnotationType())); | |||||
} else { | |||||
parameterTypeAnnotations.add(stringify(node.getResolvedAnnotationType())); | |||||
} | |||||
return node; | |||||
} | |||||
private String stringify(ResolvedType resolvedAnnotationType) { | |||||
return "@"+resolvedAnnotationType.getSimpleName(); | |||||
} | |||||
public Object visit(BindingAnnotationTypePattern node, Object data) { | |||||
stringRep.append("binding"); | |||||
return node; | |||||
} | |||||
public Object visit(NotAnnotationTypePattern node, Object data) { | |||||
stringRep.append("not"); | |||||
return node; | |||||
} | |||||
public Object visit(OrAnnotationTypePattern node, Object data) { | |||||
stringRep.append("("); | |||||
node.getLeft().accept(this, data); | |||||
stringRep.append(" or "); | |||||
node.getRight().accept(this, data); | |||||
stringRep.append(")"); | |||||
return node; | |||||
} | |||||
public Object visit(WildAnnotationTypePattern node, Object data) { | |||||
stringRep.append("wild["); | |||||
stringRep.append(node.getTypePattern().toString()); | |||||
stringRep.append("]"); | |||||
return node; | |||||
} | |||||
public Object visit(AnnotationPatternList node, Object data) { | |||||
stringRep.append("list"); | |||||
return node; | |||||
} | |||||
} | |||||
public void testAtThis() { | public void testAtThis() { | ||||
PointcutExpression atThis = parser.parsePointcutExpression("@this(org.aspectj.weaver.tools.Java15PointcutExpressionTest.MyAnnotation)"); | PointcutExpression atThis = parser.parsePointcutExpression("@this(org.aspectj.weaver.tools.Java15PointcutExpressionTest.MyAnnotation)"); | ||||
ShadowMatch sMatch1 = atThis.matchesMethodExecution(a); | ShadowMatch sMatch1 = atThis.matchesMethodExecution(a); |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
public class A { | |||||
public void a(String s) {} | |||||
public void b(@A1 String s) {} | |||||
public void c(@A1 @A2 String s) {} | |||||
public void d(@A1 String s,@A2 String t) {} | |||||
public void e(A1AnnotatedType s) {} | |||||
public void f(A2AnnotatedType s) {} | |||||
public void g(@A2 A1AnnotatedType s) {} | |||||
public void h(@A1 A1AnnotatedType s) {} | |||||
public void i(A1AnnotatedType s,@A2 String t) {} | |||||
public void j(@A1 @A2 String s) {} | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
public @interface A1 { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
@A1 | |||||
public class A1AnnotatedType { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
public @interface A2 { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
@A2 | |||||
public class A2AnnotatedType { | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
import java.lang.annotation.*; | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
public @interface A3 { | |||||
Color value() default Color.RED; | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
package test; | |||||
public class AnnoValues { | |||||
public void none() {} | |||||
@A3 public void defaultMethod() {} | |||||
@A3(Color.GREEN) public void greenMethod() {} | |||||
@A3(Color.RED) public void redMethod() {} | |||||
@A3(Color.BLUE) public void blueMethod() {} | |||||
} |
package test; | |||||
/* ******************************************************************* | |||||
* Copyright (c) 2008 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://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors | |||||
* Andy Clement | |||||
* ******************************************************************/ | |||||
public enum Color { RED, GREEN, BLUE } |