Search code examples
javaaspectjpointcut

Aspectj "after throwing" - monitor a specific exception


I'm trying to catch all MySpecificException exceptions thrown from an application code via aspectj.

There are lots of places where this exception can be thrown. Once the exception is thrown I want to log it or do some operation (regardless if it was caught later or not).

I've tried using:

@AfterThrowing(value = "(execution(* *.*(..))), throwing = "throwable")

but this is an overkill since it catches all the exceptions. I can filter manually later, but I'm trying to avoid this (due to my apps nature, it causes load time problems in some cases due to class loader issues)

I've also tried:

@AfterThrowing(value = "(execution(* *.*(..))) throws MySpecificException, throwing = "throwable")

but it's not enough since what if the method declares that it throws lots of exceptions?

Any suggestions on how to catch only my relevant exceptions without filtering them inside the pointcut implementation?

Thanks


Solution

  • Your code is not executable, please provide an MCVE or at least a full aspect next time. You do not even provide the advice's signature. This is not a good way to ask questions on SO. As a user with 1,000+ reputation points you should know that.

    Anyway, the answer to your question is actually very simple. Assuming you have this sample code:

    Exception class + driver application:

    package de.scrum_master.app;
    
    public class MySpecificException extends Exception {
      private static final long serialVersionUID = 1L;
    }
    
    package de.scrum_master.app;
    
    import java.io.IOException;
    
    public class Application {
      public String doSomething(Integer number) {
        return number.toString();
      }
    
      public void doSomethingElse(boolean doThrow) throws MySpecificException {
        if (doThrow)
          throw new MySpecificException();
      }
    
      public void doWhatever(boolean doThrow) throws MySpecificException, IOException {
        if (doThrow)
          throw new MySpecificException();
        else
          throw new IOException();
      }
    
      public static void main(String[] args) throws MySpecificException, IOException {
        Application application = new Application();
    
        // Just so as not to mess up the console output in the IDE for this demo
        System.setErr(System.out);
    
        // No exceptions here
        application.doSomething(11);
        application.doSomethingElse(false);
    
        // Let's catch some exceptions
        try {
          application.doSomethingElse(true);
        } catch (MySpecificException e) {
          System.out.println("Caught " + e);
        }
        try {
          application.doWhatever(true);
        } catch (MySpecificException e) {
          System.out.println("Caught " + e);
        }
        try {
          application.doWhatever(false);
        } catch (IOException e) {
          System.out.println("Caught " + e);
        }
    
        // Do not catch this one
        application.doSomethingElse(true);
      }
    }
    

    Console log without aspect:

    Caught de.scrum_master.app.MySpecificException
    Caught de.scrum_master.app.MySpecificException
    Caught java.io.IOException
    Exception in thread "main" de.scrum_master.app.MySpecificException
        at de.scrum_master.app.Application.doSomethingElse(Application.java:12)
        at de.scrum_master.app.Application.main(Application.java:50)
    

    No surprises here. We have caught and uncaught exceptions of different types. Now we want to have an aspect logging specifically all occurrences of MySpecificException, no matter if they get caught or not.

    Aspect:

    package de.scrum_master.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    
    import de.scrum_master.app.MySpecificException;
    
    @Aspect
    public class ExceptionLogger {
      @AfterThrowing(value = "(execution(* *.*(..)))", throwing = "mySpecificException")
      public void logException(JoinPoint thisJoinPoint, MySpecificException mySpecificException) {
        System.out.println(thisJoinPoint + " -> " + mySpecificException);
      }
    }
    

    See the advice method's signature? Just limit the exception parameter to the desired type.

    Console log with aspect:

    execution(void de.scrum_master.app.Application.doSomethingElse(boolean)) -> de.scrum_master.app.MySpecificException
    Caught de.scrum_master.app.MySpecificException
    execution(void de.scrum_master.app.Application.doWhatever(boolean)) -> de.scrum_master.app.MySpecificException
    Caught de.scrum_master.app.MySpecificException
    Caught java.io.IOException
    execution(void de.scrum_master.app.Application.doSomethingElse(boolean)) -> de.scrum_master.app.MySpecificException
    execution(void de.scrum_master.app.Application.main(String[])) -> de.scrum_master.app.MySpecificException
    Exception in thread "main" de.scrum_master.app.MySpecificException
        at de.scrum_master.app.Application.doSomethingElse(Application.java:12)
        at de.scrum_master.app.Application.main(Application.java:50)