Bug 103268 - Problem with improper multiple worker object instantiations
Summary: Problem with improper multiple worker object instantiations
Status: RESOLVED INVALID
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: DEVELOPMENT   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 1.5.0 M4   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-07-10 02:01 EDT by Ron Bodkin CLA
Modified: 2005-11-05 02:47 EST (History)
0 users

See Also:


Attachments
testcase patch (2.77 KB, patch)
2005-09-26 03:51 EDT, Helen Beeken CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ron Bodkin CLA 2005-07-10 02:01:21 EDT
The following program shows the advice that fires after constructing a request 
context is running TWICE after a single matching join point, always from the 
same line. Notice also that only one instance of the request context class is 
ever constructed.

However, if you comment out the second concrete subaspect that matches, then 
it correctly runs once. The second subaspect is never actually executed in 
this program. It must have something to do with handling non-static inner 
classes in concrete subaspects. 

This bug is affecting the code for my AOP@Work article and (when you see the 
article), you'll see there is an important use case... (whew)

Program:
public abstract aspect WorkerExample {

    after() returning (RequestContext newContext) : call(RequestContext+.new
(..)) {        
        System.out.println("constructing "+newContext+" 
at "+thisJoinPoint.toLongString()+" 
from "+thisEnclosingJoinPointStaticPart+":");
    }

    public abstract class RequestContext {
        public RequestContext() {
            System.out.println("new rc");
        }
        
        public final Object execute() {
            return doExecute();
        }
        
        /** template method */
        public abstract Object doExecute();
    }

    public static void main(String args[]) {
        new Runnable() {
            public void run() {}
        }.run();
    };
}

aspect ConcreteAlpha extends WorkerExample {

    Object around(final Object runnable) : execution(void Runnable.run()) && 
this(runnable) {
        System.out.println("monitoring operation: "+runnable+" 
at "+thisJoinPoint+", for "+thisJoinPoint.getThis());
        RequestContext requestContext = new RequestContext() {
            public Object doExecute() {
                return proceed(runnable);
            }
            
        };
        return requestContext.execute();
    }
    
}

aspect ConcreteBeta extends WorkerExample {
    
    Object around() : call(void awqeyuwqer()) {
        RequestContext requestContext = new RequestContext() {
            public Object doExecute() {                
                return proceed();
            }
            
        };
        return requestContext.execute();
    }

    
}

Actual output:
monitoring operation: WorkerExample$1@1b54de at execution(void 
WorkerExample.1.run()), for WorkerExample$1@1b54de
new rc
constructing ConcreteAlpha$1@17963c at call(ConcreteAlpha.1(ConcreteAlpha, 
WorkerExample, java.lang.Object, org.aspectj.runtime.internal.AroundClosure)) 
from execution(ADVICE: Object ConcreteAlpha.ajc$around$ConcreteAlpha$1$1a7ddbed
(Object, AroundClosure, JoinPoint)):
constructing ConcreteAlpha$1@17963c at call(ConcreteAlpha.1(ConcreteAlpha, 
WorkerExample, java.lang.Object, org.aspectj.runtime.internal.AroundClosure)) 
from execution(ADVICE: Object ConcreteAlpha.ajc$around$ConcreteAlpha$1$1a7ddbed
(Object, AroundClosure, JoinPoint)):

Expected output (achieved with ConcreteBeta not included):
monitoring operation: WorkerExample$1@1b54de at execution(void 
WorkerExample.1.run()), for WorkerExample$1@1b54de
new rc
constructing ConcreteAlpha$1@17953c at call(ConcreteAlpha.1(ConcreteAlpha, 
WorkerExample, java.lang.Object, org.aspectj.runtime.internal.AroundClosure)) 
from execution(ADVICE: Object ConcreteAlpha.ajc$around$ConcreteAlpha$1$1a7ddbed
(Object, AroundClosure, JoinPoint)):
Comment 1 Adrian Colyer CLA 2005-08-26 11:35:45 EDT
for investigation in M4
Comment 2 Helen Beeken CLA 2005-09-26 03:51:04 EDT
Created attachment 27502 [details]
testcase patch

The attached patch is to be applied to the tests project and reproduces the
failure with a simplified testcase.
Comment 3 Adrian Colyer CLA 2005-10-28 06:43:13 EDT
concrete advice in abstract aspects is always run once for each concrete sub-aspect - this has been the 
way in AspectJ for ever AFAIR. The program below is working as designed. Concrete advice in abstract 
aspects should be used with care!
Comment 4 Ron Bodkin CLA 2005-11-05 02:47:27 EST
Of course, you are right. What I need to do here is wrap the advice in a static 
inner concrete aspect, so it will run just once!