Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] Proper behavior of overloaded pointcut definitions

Hi Ron -

This is a good find and would make a good bug/test case.
The programming guide says,

  It is an error for two pointcuts to be named with the same
  name in the same class or aspect declaration.

When I compile with overloaded pointcut names, I do get an error.

    pointcut pc(Runnable r) : target(r) && call(void run());
    pointcut pc(SubRunnable r) : target(r) && call(void run());

 $ aspectj-1.1.1 -classpath $ajrt11 OverloadedPointcut.java
 ...\OverloadedPointcut.java:14 duplicate pointcut name: pc
 ...\OverloadedPointcut.java:15 duplicate pointcut name: pc

It's possible when this check is is omitted when it is deferred
until weave-time by binary weaving, and a bug report is in order.

When I use these pointcuts with bound parameters, I get an error.

    before(Runnable r) : pc(r) { log("pc(Runnable r)"); }
    before(SubRunnable r) : pc(r) { log("pc(SubRunnable r)"); }

When I use these pointcuts with type parameters, I get no errors.

    before() : pc(Runnable) { log("pc(Runnable)"); }
    before() : pc(SubRunnable) { log("pc(SubRunnable)"); }
    before() : pc(*) { log("pc(*)"); }

That seems like we'd require an error if overloaded pointcut names
were allowed, and we might want one in any case.

Wes

P.S. - I'd be interested in knowing why pointcuts names cannot be
overloaded.  In principle, it seems like the compiler
and weaver can staticly determine the pointcut based on the
static type of the arguments.  I might agree that overloaded
pointcut names are not good style and can lead to errors,
but I can imagine cases where overloading makes sense to
associate otherwise identical pointcuts.

Allowing overloading would mean the exact type specified should be
required, even when binding a variable.  In particular, it
doesn't make sense to me to permit type patterns when referring
to named pointcuts:

  RunnablePointcuts.runnableCalls(*, caller)

Here's what an error should look like:

  interface SubRunnable extends Runnable {}

  ...

  before(SubRunnable subrunnable, {type} caller) : ...
     RunnablePointcuts.runnableCalls(subrunnable, caller)
                                     ^^^^^^^^^^^
  ...: error: expected {parameter of type} "Runnable"
       or "SpecialRunnable", but got type "SubRunnable"

This rule should permit the full "pointcut signature" (if you will)
to be used to determine which pointcut is used when compiling
a compound pointcut.

-----

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

aspect A {
    declare parents: C implements Runnable;
    declare parents: C implements SubRunnable;
    interface SubRunnable extends Runnable {}

    pointcut pc(Runnable r) : target(r) && call(void run());
    pointcut pc(SubRunnable r) : target(r) && call(void run());
    before(Runnable r) : pc(r) { log("pc(Runnable r)"); }
    before(SubRunnable r) : pc(r) { log("pc(SubRunnable r)"); }
    before() : pc(Runnable) { log("pc(Runnable)"); }
    before() : pc(SubRunnable) { log("pc(SubRunnable)"); }
    before() : pc(*) { log("pc(*)"); }
    void log(String s) { System.out.println(s); }
}

Ron Bodkin wrote:

What is considered to be the proper behavior of overloaded pointcut definitions? For example, the following program compiles with no warnings, produces no output when run under AspectJ 1.1.1.  It appears to behave as if the more specific definition is the only definition of the pointcut.

Here is a simple program that illustrates the question and odd behavior:

package lib;

public class RunnablePointcuts {
    public pointcut runnableCalls(Runnable runnable, Object caller) :
        call(* run(..)) && target(runnable) && this(caller);

    //public pointcut specialRunnableCalls(SpecialRunnable runnable, Object caller) :
    public pointcut runnableCalls(SpecialRunnable runnable, Object caller) :
        call(* run(..)) && target(runnable) && this(caller);
}
---
package lib;

public interface SpecialRunnable extends Runnable {
}
---
package client;

import lib.RunnablePointcuts;
import lib.SpecialRunnable;

public aspect Use {
    before(Object caller) : RunnablePointcuts.runnableCalls(*, caller) && target(MyRunnable) {
        System.out.println("my runnable called from "+caller);
    }
    public static void main(String args[]) {
	Use.aspectOf().doIt();
    }
    public void doIt() {
        new MyRunnable().run();
    }
}

// the advice will run if you make this implement SpecialRunnable
//class MyRunnable implements SpecialRunnable {
class MyRunnable implements Runnable {
    public void run() {}
}


...

I ask this because I ran into a bug when compiling client code like this that gives these errors when using a jar on the aspectpath, whereas if you include the source in the project it works fine. E.g.,

compile:
     [iajc] C:\eclipse\workspace\atrack\src\server\org\atrack\ui\error\TestBug.j
ava:30 incompatible type, expected javax.servlet.ServletRequest found BindingTyp
ePattern(javax.servlet.http.HttpServletRequest, 2)
     [iajc] C:\eclipse\workspace\atrack\src\server\org\atrack\ui\error\TestBug.j
ava:30 can't find referenced pointcut

I think the answer is to make overloaded PCD's an error. Also, please let me know if it's worth my trying to isolate this bug in a reproducable test case.

Ron

Ron Bodkin
Chief Technology Officer
New Aspects of Security
m: (415) 509-2895
_______________________________________________
aspectj-dev mailing list
aspectj-dev@xxxxxxxxxxx
http://dev.eclipse.org/mailman/listinfo/aspectj-dev




Back to the top