@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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; |
@@ -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++; | |||
} | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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); |
@@ -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) {} | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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; | |||
} |
@@ -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() {} | |||
} |
@@ -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 } |