Community
Participate
Working Groups
It should be possible to use 'if' pointcut during load-time weaving. It doesn't seem to work now over than for simple 'if(true)' / 'if(false)' expressions. Consider the following test-case: __________________________________________________________________________ AopService.java: __________________________________________________________________________ package com.spring.aop; public class AopService implements AopInterface<Number> { public void service(Number o) { System.out.println("xxxxx: AopService.service()"); } } __________________________________________________________________________ __________________________________________________________________________ TestAspect.java __________________________________________________________________________ package com.spring.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class TestAspect { @Around("execution(* com.spring.aop.AopService.*(..)) && if(java.lang.System.currentTimeMillis() > 1)") public Object advice(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("xxxxxxxxxxxx: TestAspect.advice(): aspect is called on " + joinPoint + ". This object: " + joinPoint.getThis()); return joinPoint.proceed(); } } __________________________________________________________________________ __________________________________________________________________________ aop.xml __________________________________________________________________________ <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver options="-verbose -showWeaveInfo"> </weaver> <aspects> <aspect name="com.spring.aop.TestAspect"/> </aspects> </aspectj> __________________________________________________________________________ __________________________________________________________________________ AAA.java __________________________________________________________________________ package com; import com.spring.aop.AopService; public class AAA { public static void main(String[] args) throws Exception { AopService aopService = new AopService(); aopService.service(null); } } __________________________________________________________________________ The classes are compiled and the program is started by the following command: java -cp . -javaagent:PATH_TO_ASPECTJ/bin/aspectjweaver.jar com.AAA Output: C:\temp\classes>java -cp . -javaagent:C:\dev\aspectj\1.6.2\bin\aspectjweaver.jar com.AAA [AppClassLoader@13f5d07] info AspectJ Weaver Version 1.6.2 built on Saturday Oct 4, 2008 at 05:47:07 GMT [AppClassLoader@13f5d07] info register classloader sun.misc.Launcher$AppClassLoader@13f5d07 [AppClassLoader@13f5d07] info using configuration /C:/temp/classes/META-INF/aop.xml [AppClassLoader@13f5d07] info register aspect com.spring.aop.TestAspect [AppClassLoader@13f5d07] error at com\spring\aop\TestAspect.java::0 Invalid pointcut 'execution(* com.spring.aop.AopService.*(..)) && if(java.lang.System.c urrentTimeMillis() > 1)': org.aspectj.weaver.patterns.ParserException: ) at position 51 xxxxx: AopService.service() Please note that weaving settings are correct because if I change pointcut expression to the '@Around("execution(* com.spring.aop.AopService.*(..))")' everything works fine - aspect is weaved and applied. Find the files with the mentioned source at the attach.
Created attachment 118667 [details] test-case source and output
Correction: AopService class from the test-case shouldn't implement any interface, i.e. the following row public class AopService implements AopInterface<Number> { should be changed to public class AopService
I'm afraid annotation style if() does not work the same as code style if(). We don't support the embedding of arbitrary bits of Java in a string as it would be too difficult to compile. And so, as per the "if() pointcut expressions" section in: http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-pcadvice.html You have to supply an empty if() and the code for the if in a method body. For example, this refactoring of your code works fine: @Aspect public class X { @Pointcut("execution(* AopService.*(..)) && if()") public static boolean foo() { return System.currentTimeMillis()>1; } @Around("foo()") public Object advice(ProceedingJoinPoint joinPoint) throws Throwable {...} } Because the pointcut is in a string, javac will not see anything wrong with the pointcut and so it fails at loadtime indicating the bad pointcut (it could be more clear with its message though). If using ajc to compile the annotation style aspect, it will fail but (again) the message is hopeless: C:\temp\foo\X.java:16 [error] Syntax error on token "execution(* AopService.*(..)) && if(java.lang.System.currentTimeMillis() > 1)", ")" expected @Around("execution(* AopService.*(..)) && if(java.lang.System.currentTimeMillis() > 1)") So - I'll leave this bug open to cover improving the messages in both cases. But it is working as designed.
Thank you very much for clarification. It was my fault that I didn't find exact explanation of 'if' pointcut usage during annotation-based configuration. I tested the mentioned approach and have one more question now. Suppose we change the aspect class and starter class as follows: __________________________________________________________________________ TestAspect.java __________________________________________________________________________ package com.spring.aop; import org.aspectj.lang.annotation.*; @Aspect public class TestAspect { @Pointcut("execution(* com.spring.aop..*(java.lang.Number)) && args(i) && if()") public static boolean someCallWithIfTest(Number i) { return i.longValue() > 5; } @Before("someCallWithIfTest(i)") public void beforeAdviceWithRuntimeTest(Number i) { System.out.println("xxxxxxxxxxxxx: TestAspect.beforeAdviceWithRuntimeTest() called"); } } __________________________________________________________________________ AAA.java __________________________________________________________________________ package com; import com.spring.aop.AopService; public class AAA { public static void main(String[] args) throws Exception { AopService aopService = new AopService(); aopService.service(1); aopService.service(10); } } I expect aspect to be applied only to the second aopService.service() execution then. However, I got the following: [AppClassLoader@13f5d07] info register aspect com.spring.aop.TestAspect [AppClassLoader@13f5d07] weaveinfo Join point 'method-execution(void com.spring.aop.AopService.service(java.lang.Number))' in Type 'com.spring.aop.AopS ce' (AopService.java:6) advised by before advice from 'com.spring.aop.TestAspect' (TestAspect.java) [with runtime test] [AppClassLoader@13f5d07] weaveinfo Join point 'method-execution(boolean com.spring.aop.TestAspect.someCallWithIfTest(java.lang.Number))' in Type 'com.s g.aop.TestAspect' (TestAspect.java:10) advised by before advice from 'com.spring.aop.TestAspect' (TestAspect.java) [with runtime test] Exception in thread "main" java.lang.StackOverflowError at com.spring.aop.TestAspect.someCallWithIfTest(TestAspect.java) at com.spring.aop.TestAspect.someCallWithIfTest(TestAspect.java:10) at com.spring.aop.TestAspect.someCallWithIfTest(TestAspect.java:10) at com.spring.aop.TestAspect.someCallWithIfTest(TestAspect.java:10) ..... I dumped generated classes and decompiled them. TestAspect looks wierd: __________________________________________________________________________ package com.spring.aop; import java.io.PrintStream; import org.aspectj.lang.NoAspectBoundException; public class TestAspect { public TestAspect() { } public static boolean someCallWithIfTest(Number i) { Number number = i; if(someCallWithIfTest(number)) aspectOf().beforeAdviceWithRuntimeTest(number); return i.longValue() > 5L; } public void beforeAdviceWithRuntimeTest(Number i) { System.out.println("xxxxxxxxxxxxx: TestAspect.beforeAdviceWithRuntimeTest() called"); } public static TestAspect aspectOf() { if(ajc$perSingletonInstance == null) throw new NoAspectBoundException("com.spring.aop.TestAspect", ajc$initFailureCause); else return ajc$perSingletonInstance; } public static boolean hasAspect() { return ajc$perSingletonInstance != null; } private static void ajc$postClinit() { ajc$perSingletonInstance = new TestAspect(); } private static Throwable ajc$initFailureCause; /* synthetic field */ public static final TestAspect ajc$perSingletonInstance; /* synthetic field */ static { try { ajc$postClinit(); } catch(Throwable throwable) { ajc$initFailureCause = throwable; } } } __________________________________________________________________________ I.e. join point condition is injected to the pointcut method ('if' and its body), hence, the method calls itself recursively . If I change aspect as follows, everything works as expected. However, the reference you mentioned says that 'Extra implicit arguments of type JoinPoint, JoinPoint.StaticPart and JoinPoint.EnclosingStaticPart can also be used', i.e. that attributes are not mandatory for the 'if' pointcut. Can you advice on that? package com.spring.aop; import org.aspectj.lang.annotation.*; import org.aspectj.lang.JoinPoint; @Aspect public class TestAspect { @Pointcut("execution(* com.spring.aop..*(java.lang.Number)) && args(i) && if()") public static boolean someCallWithIfTest(Number i, JoinPoint jp, JoinPoint.EnclosingStaticPart esjp) { return i.longValue() > 5; } @Before("someCallWithIfTest(i, jp, enc)") public void beforeAdviceWithRuntimeTest(Number i, JoinPoint jp, JoinPoint.EnclosingStaticPart enc) { System.out.println("xxxxxxxxxxxxx: TestAspect.beforeAdviceWithRuntimeTest() called"); } }
I believe it is simply that your pointcut method matches the signature you specified for execution(* com.spring.aop..*(java.lang.Number)) - hence it gets advised. By adding the extra parameters (that have no real use to you) you simply ensure it no longer matches. I would write your pointcut so you are not advising elements of your aspect, since that really doesn't seem to be what you want to do: @Pointcut("execution(* com.spring.aop..*(java.lang.Number)) && args(i) && if() && !within(com.spring.aop.TestAspect)")
Such a silly mistake :( Thank you very much.
improved message: "in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
Excellent, thanks!