yegor256
yegor256

Reputation: 105213

How to initialize AspectJ aspect without using a constructor?

My AspectJ aspect looks like this:

@Aspect
public class MyAspect {
  private Child child;
  public MyAspect() {
    this.child = new Child();
  }
  @Around("... skipped ...")
  public Object wrap(ProceedingJoinPoint point) throws Throwable {
    // some custom functionality
    return point.proceed();
  }
}

This doesn't work because during the construction of Child a wrap() pointcut gets called and it leads to a runtime exception, since an instance of MyAspect is not yet ready.

Is it possible to tell AspectJ somehow to call some method of MyAspect right after its instantiating?

Upvotes: 1

Views: 3876

Answers (2)

kriegaex
kriegaex

Reputation: 67457

New answer:

Here is a sample driver class Child:

public class Child {
    private String name;

    public Child(String name) {
        this.name = name;
        System.out.println("Constructing child named " + this.name);
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public static void main(String[] args) {
        Child myChild = new Child("Penélope");
        System.out.println("My child is named " + myChild.getName());
        myChild.setName("María Elena");
        System.out.println("My child is now named " + myChild.getName());
    }
}

And here is an aspect MyAspect intercepting public method and constructor executions of Child, but excluding the aspect constructor:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {
    private Child child;

    public MyAspect() {
        child = new Child("Scarlett");
        System.out.println("Aspect child is named " + child.getName());
        child.setName("Cristina");
        System.out.println("Aspect child is now named " + child.getName());
    }

    @Around(
        "(execution(public * Child.*(..)) || execution(public Child.new(..)))" +
        "&& !cflow(initialization(MyAspect.new()))"
    )
    public Object wrap(ProceedingJoinPoint point) throws Throwable {
        System.out.println(point.getStaticPart());
        return point.proceed();
    }
}

This is the sample output:

Constructing child named Scarlett
Aspect child is named Scarlett
Aspect child is now named Cristina
execution(void Child.main(String[]))
execution(Child(String))
Constructing child named Penélope
execution(String Child.getName())
My child is named Penélope
execution(void Child.setName(String))
execution(String Child.getName())
My child is now named María Elena

You can see that no Child joinpoints are intercepted during aspect construction. BTW, otherwise you would get NoAspectBoundException anyway. ;-)


Old answer:

You can combine your pointcut with something like (untested):

... && !cflow(MyAspect.new())

Ths should exclude what you do not want intercepted.

Upvotes: 3

Andrew Eisenberg
Andrew Eisenberg

Reputation: 28757

Perhaps you are best off trying to do the initialization inside of an advice. Eg-

after() : execution(MyAspect.new()) {
  this.child = new Child();
}

But really, this strikes me as bad form. Having advice of the containing aspect being applied somewhere during the construction of Child seems like a circular dependency. I'd try to refactor (perhaps into multiple aspects) in order to avoid the circularity.

Upvotes: 0

Related Questions