Community
Participate
Working Groups
The code below overflows when concretizing a circular pointcut from a parameterized aspect. Not true when the aspect is not parameterized. --------------------------------------------- public class SelfPC { public static void main(String[] args) { new C().foo(); } static class C { pointcut doit() : C.doit(); // CE expected void foo() {} } // ------------ pertarget<T> static abstract aspect PT_PARM<T> pertarget(pc()) { abstract protected pointcut pc(); before() : pc() {} } static aspect CPT_PARM extends PT_PARM<C> { protected pointcut pc() : C.doit(); } // // ------------ issingleton<T> // static abstract aspect IS_PARM<T> { // abstract protected pointcut pc(); // before() : pc() {} // } // static aspect CIS_PARM extends IS_PARM<C> { // protected pointcut pc() : C.doit(); // } // // ------------ pertarget // static abstract aspect PT pertarget(pc()) { // abstract protected pointcut pc(); // before() : pc() {} // } // static aspect CPT extends PT{ // protected pointcut pc() : C.doit(); // } // // ------------ issingleton // static abstract aspect SIS { // abstract protected pointcut pc(); // before() : pc() {} // } // static aspect CSIS extends SIS { // protected pointcut pc() : C.doit(); // } } --------------------------------------------- java.lang.StackOverflowError at java.lang.StringBuffer.append(StringBuffer.java:225) at org.aspectj.weaver.UnresolvedType.nameToSignature(UnresolvedType.java:734) at org.aspectj.weaver.UnresolvedType.forName(UnresolvedType.java:308) at org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory.fromBinding(EclipseFactory.java:302) at org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory.fromEclipse(EclipseFactory.java:129) at org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType.getSuperclass(EclipseSourceType.java:119) at org.aspectj.weaver.ReferenceType.getSuperclass(ReferenceType.java:481) at org.aspectj.weaver.ResolvedType.getDirectSupertypes(ResolvedType.java:65) at org.aspectj.weaver.ResolvedType$6.get(ResolvedType.java:447) at org.aspectj.weaver.Iterators$4.next(Iterators.java:148) at org.aspectj.weaver.Iterators$3$1.hasNext(Iterators.java:117) at org.aspectj.weaver.Iterators$3.hasNext(Iterators.java:128) at org.aspectj.weaver.ResolvedType.findPointcut(ResolvedType.java:466) at org.aspectj.weaver.patterns.ReferencePointcut.concretize1(ReferencePointcut.java:269) at org.aspectj.weaver.patterns.Pointcut.concretize(Pointcut.java:229) at org.aspectj.weaver.patterns.ReferencePointcut.concretize1(ReferencePointcut.java:326) at org.aspectj.weaver.patterns.Pointcut.concretize(Pointcut.java:229) ... ---------------------------------------------
I've managed to recreate the problem with the following simplified testcase: abstract aspect ParameterizedAbstractAspect<T>{ abstract protected pointcut pc(); before() : pc() {} } aspect ParameterizedConcrete extends ParameterizedAbstractAspect<ParameterizedConcrete> { protected pointcut pc() : pc(); } The reason the StackOverflowError is occuring is in ReferencePointcut.concretize1(...). In this method, there is a flag called "concretizing" which is initially false but is set to true when concretizing is taking place. The method begins with a check on whether or not "concretizing" is true and if it is then the expected error message is produced - 'circular pointcut declaration involving: pc()' type message. If it's false, then we go ahead and try to concretize. The part of the method which is causing the problems is: Pointcut ret = pointcutDec.getPointcut(); if (typeVariableMap != null) ret = ret.parameterizeWith(typeVariableMap); return ret.concretize(searchStart, declaringType, newBindings); (note that the implementation of concretize calls the concretize1 method). If the aspect is not parameterized then typeVariableMap == null. However, if it is parameterized then typeVariableMap is non-null. In this case, ret becomes a new object (due to the implementation of ReferencePointcut.parameterizeWith(..)). So, for example, if we're looking at non-parameterized aspects, we get the following info at the trouble spot in concretize1: first pass in concretize1: this: id = 144 concretizing is set to true, ret : id = 176 concretizing is still false second pass in concretize1: this: id = 176 concretizing is set to true ret : id = 176 concretizing is still true third pass in concretize1: this: id = 176 concretizing is true so get compiler warning as expected However, if we're looking at parameterized aspects, we get the following: first pass in concretize1: this : id = 47 concretizing is set to true ret (before call to parameterizeWith(..) : id = 92 concretizing is false ret (after call to parameterizeWith(..) : id = 95 concretizing is false second pass in concretize1: this : id = 95 concretizing is set to true ret (before call to parameterizeWith(..) : id = 92 concretizing is false ret (after call to parameterizeWith(..) : id = 135 concretizing is false third pass in concretize1: this : id = 135 concretizing set to true ret (before call to parameterizeWith(..) : id = 92 concretizing is false ret (after call to parameterizeWith(..) : id = 147 concretizing is false this goes on and on..... and hence the StackOverflowError.
The fix is to add a protected boolean field hasBeenParameterized to the abstract class Pointcut. Then add an extra check in the problem code mentioned in comment #1, changing it from if (typeVariableMap != null) ret = ret.parameterizeWith(typeVariableMap); to if (typeVariableMap != null && !hasBeenParameterized) { ret = ret.parameterizeWith(typeVariableMap); ret.hasBeenParameterized=true; } It is necessary to update the field here rather than in the ReferencePointcut.parameterizeWith(...) method, because parameterizeWith is called several times from different places whereas you only concretize once.
Created attachment 29852 [details] patch containing fix Apply the patch to the weaver project. The patch contains the fix described in the previous comment.
Created attachment 29853 [details] patch containing testcases Apply this patch to the tests project. This patch contains the original failing testcase in file pr115325.aj. I've also included another testcase in file pr115325b.aj which came about from me investigating difference scenarios. I'm not sure whether it should be included in the suite, however, I thought I would include it in the patch just in case :-)
fix available.