简体   繁体   中英

How to catch all newly created objects of type or subtype Widget with AspectJ?

In order to get all newly instantiated widgets I tried the following code

after(final Widget widget) : execution (* Widget+.new(..)) && this(widget) {
    ...
}

but it fails hard every time there are chained constructors (several constructors in the same class, mutually referring).

I'm in need of collecting all the kinds of widgets that are created in an application. I can't use call instead of execution because that would mean the woven code would become part of the calling code, and not of the Widget code, which is troublesome as there are lots of libraries involved in this project, and that would make me have to weave all of them in order to accomplish the described endeavor.

Thanks

Edit (more info)

Consider the following class:

class A {
  private int i;

  public A(int i) {
    this.i = i;
    initialize();
  }

  public A() {
    this(0);
  }
}

after(final A a) : execution (* A+.new(..)) && this(a) {
  ...
}

//test
new A(0); //caught by the aspect and fine
new A(); //caught by the aspect twice, once for every constructor.

The situation gets even worse if you consider an hierarchy of A s:

class B extends A {
  public B() {
    super();
  }

  public B(int i) {
    super(i);
  }
}

//test
new B(0); //caught by the aspect twice, once as B and once as A
new A(); //caught by the aspect thrice, once for B and twice for A

I'd like to only catch the object once, and only after the object is totally constructed (that is, it has run the "outer" constructor to the end), being the aspect code injected into the class under consideration and not outside it (so a call wouldn't be acceptable).

There's an interesting discussion I found the other about this topic on the AspectJ mailing lists: http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg09651.html . It describes a possible (non-complete if I am not wrong) solution, involving some sort of stack analysis.

Edit2

This simply hack seems to do the trick:

after(A a) : initialization(A+.new(..)) && this(a) {
    if (a.getClass() == thisJoinPoint.getSignature().getDeclaringType())
                //fully constructed object caught
}

In your case, you should be able to use the initialization pointcut. See the AspectJ docs for more info on that pointcut. Essentially, you should do something like this:

after(final A a) : initialization (* A+.new(..)) && this(a) {
  ...
}

The nice thing here is that you can be tricky and specify a specific constructor. In the following case, only the 1-arg constructor is matched. 0-arg constrcutor is not.

initialization (* A+.new(int))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM