]> source.dussan.org Git - aspectj.git/commitdiff
big refactoring
authoraclement <aclement>
Fri, 9 May 2008 16:13:55 +0000 (16:13 +0000)
committeraclement <aclement>
Fri, 9 May 2008 16:13:55 +0000 (16:13 +0000)
17 files changed:
weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java
weaver5/java5-src/org/aspectj/weaver/reflect/Java15ReflectionBasedReferenceTypeDelegate.java
weaver5/java5-src/org/aspectj/weaver/tools/Jdk14Trace.java
weaver5/java5-testsrc/CounterAspect.java [new file with mode: 0644]
weaver5/java5-testsrc/MA.java [new file with mode: 0644]
weaver5/java5-testsrc/MB.java [new file with mode: 0644]
weaver5/java5-testsrc/MC.java [new file with mode: 0644]
weaver5/java5-testsrc/MD.java [new file with mode: 0644]
weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java
weaver5/java5-testsrc/test/A.java [new file with mode: 0644]
weaver5/java5-testsrc/test/A1.java [new file with mode: 0644]
weaver5/java5-testsrc/test/A1AnnotatedType.java [new file with mode: 0644]
weaver5/java5-testsrc/test/A2.java [new file with mode: 0644]
weaver5/java5-testsrc/test/A2AnnotatedType.java [new file with mode: 0644]
weaver5/java5-testsrc/test/A3.java [new file with mode: 0644]
weaver5/java5-testsrc/test/AnnoValues.java [new file with mode: 0644]
weaver5/java5-testsrc/test/Color.java [new file with mode: 0644]

index 4a51e98da7bcef568bae63e85e671e874037c930..fd8924b6a875cc3632597a2c9c0778d0dc9a91a0 100644 (file)
@@ -21,11 +21,14 @@ import java.util.Collections;
 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;
@@ -96,6 +99,74 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
                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
@@ -106,7 +177,12 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
                        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();
@@ -189,6 +265,8 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
        }
        
        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...
@@ -200,4 +278,70 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
                }
                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;
+       }
+       
 }
index b5d63d7d1ee44c877a5cf5859a55a1f31872257e..629a0f441cb2064fa731472526babd5537431916 100644 (file)
@@ -17,6 +17,8 @@ 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;
@@ -31,6 +33,7 @@ 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;
 
 /**
@@ -64,6 +67,7 @@ public class Java15ReflectionBasedReferenceTypeDelegate extends
                annotationFinder = new Java15AnnotationFinder();
                argNameFinder = annotationFinder;
                annotationFinder.setClassLoader(this.classLoader);
+               annotationFinder.setWorld(aWorld);
                this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld);
        }
        
@@ -101,10 +105,11 @@ public class Java15ReflectionBasedReferenceTypeDelegate extends
        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;
        }
@@ -141,24 +146,25 @@ public class Java15ReflectionBasedReferenceTypeDelegate extends
                }
                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;
@@ -170,14 +176,15 @@ public class Java15ReflectionBasedReferenceTypeDelegate extends
                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;
        }
@@ -250,6 +257,11 @@ public class Java15ReflectionBasedReferenceTypeDelegate extends
                        } 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
index 7072ffcb6f479ac197172e6b0d9aad05e5537dfc..061b0b0a04699cebb563a935bff46dc239698593 100644 (file)
@@ -14,6 +14,7 @@ import java.util.logging.Handler;
 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;
diff --git a/weaver5/java5-testsrc/CounterAspect.java b/weaver5/java5-testsrc/CounterAspect.java
new file mode 100644 (file)
index 0000000..1ca126d
--- /dev/null
@@ -0,0 +1,52 @@
+/* *******************************************************************
+ * 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
diff --git a/weaver5/java5-testsrc/MA.java b/weaver5/java5-testsrc/MA.java
new file mode 100644 (file)
index 0000000..2708825
--- /dev/null
@@ -0,0 +1,15 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/MB.java b/weaver5/java5-testsrc/MB.java
new file mode 100644 (file)
index 0000000..3ff3eed
--- /dev/null
@@ -0,0 +1,15 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/MC.java b/weaver5/java5-testsrc/MC.java
new file mode 100644 (file)
index 0000000..d48133b
--- /dev/null
@@ -0,0 +1,15 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/MD.java b/weaver5/java5-testsrc/MD.java
new file mode 100644 (file)
index 0000000..47a61cb
--- /dev/null
@@ -0,0 +1,15 @@
+/* *******************************************************************
+ * 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 {
+
+}
index 4a0ecb28ab2f2896611260484cb68f395aed7436..fa1e1d17deda69e3816a25a371a01b907b4f5597 100644 (file)
@@ -14,17 +14,40 @@ package org.aspectj.weaver.tools;
 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 {
@@ -41,6 +64,277 @@ 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);
diff --git a/weaver5/java5-testsrc/test/A.java b/weaver5/java5-testsrc/test/A.java
new file mode 100644 (file)
index 0000000..12959cd
--- /dev/null
@@ -0,0 +1,27 @@
+/* *******************************************************************
+ * 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) {}
+
+}
diff --git a/weaver5/java5-testsrc/test/A1.java b/weaver5/java5-testsrc/test/A1.java
new file mode 100644 (file)
index 0000000..6167083
--- /dev/null
@@ -0,0 +1,20 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/test/A1AnnotatedType.java b/weaver5/java5-testsrc/test/A1AnnotatedType.java
new file mode 100644 (file)
index 0000000..e40addb
--- /dev/null
@@ -0,0 +1,17 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/test/A2.java b/weaver5/java5-testsrc/test/A2.java
new file mode 100644 (file)
index 0000000..48749a3
--- /dev/null
@@ -0,0 +1,20 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/test/A2AnnotatedType.java b/weaver5/java5-testsrc/test/A2AnnotatedType.java
new file mode 100644 (file)
index 0000000..0fa3b5c
--- /dev/null
@@ -0,0 +1,17 @@
+/* *******************************************************************
+ * 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 {
+
+}
diff --git a/weaver5/java5-testsrc/test/A3.java b/weaver5/java5-testsrc/test/A3.java
new file mode 100644 (file)
index 0000000..ab54388
--- /dev/null
@@ -0,0 +1,19 @@
+/* *******************************************************************
+ * 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;
+}
diff --git a/weaver5/java5-testsrc/test/AnnoValues.java b/weaver5/java5-testsrc/test/AnnoValues.java
new file mode 100644 (file)
index 0000000..08301d1
--- /dev/null
@@ -0,0 +1,20 @@
+/* *******************************************************************
+ * 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() {}     
+}
diff --git a/weaver5/java5-testsrc/test/Color.java b/weaver5/java5-testsrc/test/Color.java
new file mode 100644 (file)
index 0000000..dea2593
--- /dev/null
@@ -0,0 +1,14 @@
+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