import java.util.HashSet;
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.LocalVariable;
import org.aspectj.apache.bcel.classfile.LocalVariableTable;
import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
import org.aspectj.apache.bcel.util.Repository;
+import org.aspectj.weaver.AnnotationX;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
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) {
if (!(onMember instanceof AccessibleObject)) return Collections.EMPTY_SET;
// 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];
if (onMember instanceof Method) {
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) {
org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor)onMember);
anns = bcelCons.getAnnotations();
}
private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) {
+ if (lvt == null)
+ return null;// pr222987 - prevent NPE
LocalVariable[] vars = lvt.getLocalVariableTable();
if (vars.length < numVars) {
// basic error, we can't get the names...
}
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.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.weaver.TypeVariableReferenceType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
+import org.aspectj.weaver.tools.PointcutDesignatorHandler;
import org.aspectj.weaver.tools.PointcutParameter;
/**
annotationFinder = new Java15AnnotationFinder();
argNameFinder = annotationFinder;
annotationFinder.setClassLoader(this.classLoader);
+ annotationFinder.setWorld(aWorld);
this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld);
}
public ResolvedMember[] getDeclaredFields() {
if (fields == null) {
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++) {
- this.fields[i] = createGenericFieldMember(reflectFields[i]);
+ rFields[i] = createGenericFieldMember(reflectFields[i]);
}
+ this.fields = rFields;
}
return fields;
}
}
if (this.typeVariables == null) {
java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters();
- this.typeVariables = new TypeVariable[tVars.length];
+ TypeVariable[] rTypeVariables = new TypeVariable[tVars.length];
// basic initialization
for (int i = 0; i < tVars.length; i++) {
- typeVariables[i] = new TypeVariable(tVars[i].getName());
+ rTypeVariables[i] = new TypeVariable(tVars[i].getName());
}
// stash it
- this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(),typeVariables);
+ 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();
- 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());
}
return this.typeVariables;
if (methods == null) {
Method[] reflectMethods = this.myType.getDeclaredMethods();
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++) {
- this.methods[i] = createGenericMethodMember(reflectMethods[i]);
+ rMethods[i] = createGenericMethodMember(reflectMethods[i]);
}
for (int i = 0; i < reflectCons.length; i++) {
- this.methods[i + reflectMethods.length] =
+ rMethods[i + reflectMethods.length] =
createGenericConstructorMember(reflectCons[i]);
}
+ this.methods = rMethods;
}
return methods;
}
} else {
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
// 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.Logger;
+// OPTIMIZE move out for now? check what doc says about using these variants on trace (commons/14)
public class Jdk14Trace extends AbstractTrace {
private Logger logger;
--- /dev/null
+/* *******************************************************************
+ * 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++;
+ }
+}
\ No newline at end of file
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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.RetentionPolicy;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
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.TestCase;
import junit.framework.TestSuite;
/**
- * @author colyer
+ * Test parameter pointcut parsing. Extended by Andy Clement to cover parameter annotation matching.
*
*/
public class Java15PointcutExpressionTest extends TestCase {
private Method c;
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() {
PointcutExpression atThis = parser.parsePointcutExpression("@this(org.aspectj.weaver.tools.Java15PointcutExpressionTest.MyAnnotation)");
ShadowMatch sMatch1 = atThis.matchesMethodExecution(a);
--- /dev/null
+/* *******************************************************************
+ * 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) {}
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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 {
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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;
+}
--- /dev/null
+/* *******************************************************************
+ * 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() {}
+}
--- /dev/null
+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 }
\ No newline at end of file