Community
Participate
Working Groups
I have created a simple test Aspect which advises methods which are annotated with @Lock.Read and @Lock.Write when belonging to a type annotated with @Lock. When debugging, I noticed that ALL classes in my eclipse project had been instrumented with extraneous fields interface's (fields / methods) even though they were not annotated with the required annotations for the aspect to advise them. The orginal PCD which worked but caused all classes to be instrumented (but not advised) was pointcut readLock(): execution(@Lock.Read * * (..)); pointcut writeLock(): execution(@Lock.Write * * (..)); When changing these definitions to pointcut readLock(): execution(@Lock.Read * (@Lock *).*(..)); pointcut writeLock(): execution(@Lock.Write * (@Lock *).*(..)); only classes annotated with @Lock on the type and @Lock.Read/Write on methods were actually instrumented. This was the desired result. Both work equally well at runtime but the orginal pcd will cause all classes to have placeholder fields and extraneous methods (as per $ajcMighHaveAspect?) even though they will _never_ be advised. The aspect: import java.util.concurrent.locks.ReentrantReadWriteLock; public abstract aspect LockAspect pertarget(fair(Lock) && (readLock() || writeLock())) { declare error: execution(@Lock.Read * * (..)) && !@within(Lock): "@Lock.Read and @Lock.Write cannot be used unless the Class/Interface is annotated with @Lock"; private ReentrantReadWriteLock.ReadLock read; private ReentrantReadWriteLock.WriteLock write; private ReentrantReadWriteLock lock; public LockAspect(boolean fair) { lock = new ReentrantReadWriteLock(fair); read = lock.readLock(); write = lock.writeLock(); } abstract pointcut fair(Lock lock); // fixed pcd // pointcut readLock(): execution(@Lock.Read * (@Lock *).*(..)); // pointcut writeLock(): execution(@Lock.Write * (@Lock *).*(..)); // broken? pcd pointcut readLock(): execution(@Lock.Read * * (..)); pointcut writeLock(): execution(@Lock.Write * * (..)); Object around(): readLock() { Object o = null; try { read.lock(); o = proceed(); } finally { read.unlock(); } return o; } Object around(): writeLock() { Object o = null; try { write.lock(); o = proceed(); } finally { write.unlock(); } return o; } } aspect UnfairLockAspect extends LockAspect { pointcut fair(Lock lock): @within(lock) && if(lock.isFair() == false); public UnfairLockAspect() { super(false); } } aspect FairLockAspect extends LockAspect { pointcut fair(Lock lock): @within(lock) && if(lock.isFair() == true); public FairLockAspect() { super(true); } } The annotation: @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Lock { /** * Whether the locks granted are being granted in a fair manner. * * @return if the lock associated with this object is fair or not. * @see java.util.concurrent.locks.ReentrantReadWriteLock#ReentrantReadWriteLock(boolean) */ public boolean isFair() default false; /** * Mark a method as having a read lock */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Read { } /** * Mark a method as having a write lock */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Write { } }
I think this is working as designed - possibly could be considered a compiler limitation. For a long time we had issues with putting the ajc$mightHaveAspect interface on too many types - it is all down to how much analysis we can do (or want to do) at weave time to reduce the set of types that it gets 'attached' to. In the 1.5.0 timeframe we did a lot of work under bug 75442 to address this for some of the per clauses - we tried an approach for pertarget but that is the one that is most difficult to optimize for and we had to remove it (see 75442 for more details). Given that you are using execution() PCDs - can you change from pertarget to perthis() ? For this program (a cutdown variant of yours that uses perthis): @Retention(RetentionPolicy.RUNTIME) @interface Lock { } @Retention(RetentionPolicy.RUNTIME) @interface Read { } @Retention(RetentionPolicy.RUNTIME) @interface Write { } aspect LockAspect perthis(fair(Lock) && (readLock() || writeLock())) { // fixed pcd // pointcut readLock(): execution(@Read * (@Lock *).*(..)); // pointcut writeLock(): execution(@Write * (@Lock *).*(..)); // broken? pcd pointcut readLock(): execution(@Read * * (..)); pointcut writeLock(): execution(@Write * * (..)); Object around(): readLock() { return proceed(); } Object around(): writeLock() { return proceed(); } pointcut fair(lock): @within(Lock) && if(lock.toString().equals("foo")); } public class Test { } @Lock class A { public void m1() {} @Read public void m2() {} @Write public void m3() {} } class B { public void m1() {} @Read public void m2() {} @Write public void m3() {} } Only type A gets the ajc$mightHaveAspect interface.
Closing as nothing to fix right now ... using execution() rather than call() will limit who gets the interface.