Search code examples
annotationshandleraspectj

in aspectj, can we define handler together with certain annotation?


I want to only do exception handle for methods that annotate with self-defined annotation,

like below

@Pointcut("@annotation(com.common.CollectException) && execution(* *(..))")
public void annotationPointCutDefinition() { }

@Before("annotationPointCutDefinition() && handler(*) && args(e)")
public void logCaughtException(JoinPoint thisJoinPoint, Throwable e) {
    //System.out.println(e.getClass().getCanonicalName());
    System.out.println("count = " +
        ", " +
        thisJoinPoint + " -> " +
        e.getClass().getCanonicalName());
}

but for a method marked with my self-defined annotation, it did not get weaved with logCaughtException function

@CollectException
public void divideByZeroWithCatch(){
    try{
        int a = 5/0;
    }
    catch (ArithmeticException e){
        System.out.println("Can not divide by zero");
    }
}

I am wrong with above usage? if so would someone pls give some advice here?


Solution

  • Interesting question. There are several problems in your aspect code:

    In your GitHub repository you use @within(x.y.CollectException). That would intercept joinpoints in annotated classes, but your example class has an annotated method, the class itself is not annotated. Therefore, that pointcut would never match.

    In your sample code here, you had the right idea to use @annotation(x.y.CollectException) in order to intercept annotated methods. You even added && execution(* (..)) so as to limit matching to execution pointcuts and exclude call ones. Otherwise the pointcut would fire twice per method in AspectJ (not in Spring AOP where there are not call joinpoints). So far, so good.

    But just like call and execution are not the same and therefore mutually exclusive, so are execution and handler. A handler joinpoint is usually somewhere inside (the control flow of) a method execution, but it is not the method execution. This is also your clue to the solution. You actually want to limit matching to exception handlers in the control flow of an annotated method:

    @Pointcut("@annotation(de.scrum_master.common.CollectException) && execution(* *(..))")
    public void annotationPointCutDefinition() { }
    
    @Before("cflow(annotationPointCutDefinition()) && handler(*) && args(e)")
    public void logCaughtException(JoinPoint thisJoinPoint, Throwable e) {
      System.out.println(thisJoinPoint + " -> " + e.getClass().getCanonicalName());
    }
    

    In your GitHub example, you will see the following line in the console log:

    handler(catch(ArithmeticException)) -> java.lang.ArithmeticException