[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] execution(method) and execution(constructor)

Hi all -

Read up in the Programming Guide, semantics section on method- and 
constructor-execution signature matching.  In Java, constructors behave 
like static methods in that they do not override a superclass implementation;
conversely, nonprivate instance methods can override a superclass method
with the same signature.  Thus, in AspectJ, the subclass implementation of
an instance method will match if the declaring type is either the subclass 
or the superclass, but the same is not true of a constructor or static
method.  (But if you specify subtypes of the supertype (e.g., Super+), then 
the supertype and any subtypes will match.)

The super calls are irrelevant except that they mean the super implementations
will be executed (so if a pointcut matches both the subclass join point and 
the superclass join point, advice on that pointcut will run for both join
points).  And AFIAK while initializers are gathered into constructor bodies
for a given class, superclass constructor bodies are not inlined into subclass
constructor bodies by virtue of implicit or explicit super calls.

This will probably be more clear if you study the program below and its output.
It just defines join points, pointcuts, and advice for constructors and static
and instance methods.  After that makes sense, uncomment the super calls and
see what happens.  You should convince yourself that there is an implicit super()
call in constructors (i.e., the explicit call is redundant unless to a constructor
with arguments) by seeing that the superclass constructor and advice run in any case.

Thanks for the question and particularly for including test code and expected output.
That goes a long way towards addressing the issue.

Wes

---- java ajsandbox.ConstructorExec
call  Foo.s()
execution(void Foo.s())  : ConstructorExec.java:33
execution(void Foo+.s()) : ConstructorExec.java:33
exec  Foo.s()
call  SubFoo.s()
execution(void Foo+.s()) : ConstructorExec.java:39
exec  SubFoo.s()
call  new SubFoo()
execution(Foo.new(..))   : ConstructorExec.java:34
execution(Foo+.new(..))  : ConstructorExec.java:34
exec  Foo.new()
execution(Foo+.new(..))  : ConstructorExec.java:41
exec  SubFoo.new()
call  f.m()
execution(void Foo.m())  : ConstructorExec.java:40
execution(void Foo+.m()) : ConstructorExec.java:40
exec  subFoo.m()

---- ajsandbox/ConstructorExec.java
package ajsandbox;

import org.aspectj.lang.JoinPoint;

public class ConstructorExec {
    public static void main(String[] args) {
        log("call  Foo.s()");
        Foo.s();
        log("call  SubFoo.s()");
        SubFoo.s();
        log("call  new SubFoo()");
        Foo f = new SubFoo();
        log("call  f.m()");
        f.m();
    }
    private static void log(String s) {
        System.out.println(s);
    }

    static class Foo {
        public static void s() { log("exec  Foo.s()");}
        public Foo() { log("exec  Foo.new()"); }
        public void m() { log("exec  foo.m()");}
    }

    static class SubFoo extends Foo {
        public static void s() { log("exec  SubFoo.s()");}
        public void m() { log("exec  subFoo.m()");}
        public SubFoo() { log("exec  SubFoo.new()");}
    }

    static aspect Testing {
        public static void log(JoinPoint jp, String label) {
            ConstructorExec.log(label + ": " + jp.getSourceLocation());
        }
        before(): execution(Foo.new(..)) {
            log(thisJoinPoint, "execution(Foo.new(..))   ");
        }
        before(): execution(void Foo.s()) {
            log(thisJoinPoint, "execution(void Foo.s())  ");
        }
        before(): execution(void Foo.m()) {
            log(thisJoinPoint, "execution(void Foo.m())  ");
        }
        before(): execution(Foo+.new(..)) {
            log(thisJoinPoint, "execution(Foo+.new(..))  ");
        }
        before(): execution(void Foo+.s()) {
            log(thisJoinPoint, "execution(void Foo+.s()) ");
        }
        before(): execution(void Foo+.m()) {
            log(thisJoinPoint, "execution(void Foo+.m()) ");
        }
    }
}



> ------------Original Message------------
> From: "Linton Ye" <lintonye@xxxxxxxxxxxxxxx>
> To: "aspectj-users@xxxxxxxxxxx" <aspectj-users@xxxxxxxxxxx>
> Date: Sun, Jun-18-2006 5:34 PM
> Subject: [aspectj-users] execution(method) and execution(constructor)
>
> Hi All
> 
> I got a question about the difference between execution 
> pointcut with methods and constructor, consider the following program:
> 
> public class TestSuperCalls {
> 	public static void main(String[] args) {
> 		Foo f = new SubFoo();
> 		f.bar();
> 	}
> }
> 
> class Foo {
> 	public void bar(){}
> }
> 
> class SubFoo extends Foo{
> 	public void bar(){super.bar();}
> 	public SubFoo(){super();}
> }
> 
> aspect Testing {
> 	after(Foo f):execution(Foo.new(..))&&target(f){
> 		System.out.println(f+" created.");
> 	}
> 	after(Foo f):execution(* Foo.bar(..))&&target(f){
> 		System.out.println(f+" bar executed.");
> 	}
> }
> 
> The output of the above program is:
> SubFoo@35ce36 created.
> SubFoo@35ce36 bar executed.
> SubFoo@35ce36 bar executed.
> 
> Notice that the first advice was executed only once, which is 
> what I expected, however, the second advice was executed twice.
> 
> If the line "super.bar();" is removed, the second advice will be 
> executed only once.
> 
> My question is, why the execution pointcut behaves differently 
> for methods and constructor?
> 
> I understand that when "super.bar();" is not present, the pointcut 
> matches because SubFoo is also a Foo, so the execution of the overriden 
> 
> method SubFoo.bar() should be also considered the execution of 
> Foo.bar().  
> 
> But why after adding a super call, the pointcut matches twice?
> And why this is different for constructors?
> 
> thanks,
> linton
> 
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>