Search code examples
javaspringaspectjspring-aop

AspectJ on children objects


I'm starting to work with AspectJ and I'm trying to do something that I don't know if it's possible. This is my code:

public abstract class MyAbstractObject<T> {
    private T myOtherObject;

    public T getMyOtherObject() {
        return myOtherObject;
    }
}

@Component
public class MyObject extends MyAbstractObject<WhateverObject> {
    
}

@Aspect
@Component
public class MyAspects {
    
    @Before("execution(* mypackage.MyAbstractObject.getMyOtherObject().set*(*))")
    public void beforeExample(JoinPoint joinPoint) {
        // DO THINGS
    }
}

This code fails, with the error:

Caused by: java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting ')' at character position 58 execution(* mypackage.MyAbstractObject.getMyOtherObject().set*(*))

However, I can intercept MyOtherObject like this, but not it's setters:

@Aspect
@Component
public class MyAspects {
    
    @Before("execution(* mypackage.MyAbstractObject.getMyOtherObject())")
    public void beforeExample(JoinPoint joinPoint) {
        // DO THINGS
    }
}

I don't want to intercept the setters of the object MyOtherObject everywhere, because this object is used in more places in the program where I don't need aspects. However I want to intercept them only when used in a class that extends MyAbstractObject.

I'm using Spring with AspectJ.

Thanks.


Solution

  • The syntax you just invented is illegal, unfortunately. You cannot describe chained method calls the ways you dreamed up.

    What you really want is to intercept method executions of type WhateverObject, not of MyAbstractObject or MyObject. I.e., your pointcut should rather bet something like

    execution(* mypackage.WhateverObject.set*(*))
    

    I am just guessing, but if you want to limit matching to control flows where the setter method is called (directly or indirectly) from getMyOtherObject(), in AspectJ your would add something like

    && cflow(execution(* mypackage.MyAbstractObject.getMyOtherObject()))
    

    to the first pointcut. But cflow pointcuts are unavailable in Spring AOP, which is what you seem to be using. So

    • either you switch to native AspectJ, which is easy to integrate into Spring applications, but can also be used outside of the Spring context because it is an idependent product,
    • or you check if Spring AOP's "lite" version of control flow pointcuts does what you need. I posted a few answers and links mentioning this almost undocumented feature here and there.

    As a native AspectJ fan who does not normally use Spring, you can imagine which option I would recommend regarding control flow pointcuts, but I think you can make your own decision.