Search code examples
javaaopaspectjthrowsthrowable

Should I avoid throwing Throwable when dealing with a method that throws Throwable?


I've got an @Aspect annotated class that is calling ProceedingJoinPoint#proceed(). This method throws Throwable and thus the class looks something like this:

@Aspect
@Component
public class MyClass{

    @Around("@annotation(myAnnotation)")
    public Object myMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
        //some code here
        try {
            return joinPoint.proceed();
        } finally {
            //some more code here
        }
    }
}

Is it ok for myMehtod to throw a Throwable in this scenario where I have to call another method that throws Throwable? Should I avoid throwing Throwable and somehow convert it to Exception or Error?

In either case I'd like to know why as well. Thank you.


Solution

  • No, it is not okay to throw Throwable. Errors and unchecked exceptions are not supposed to be caught; Errors are serious or fatal system problems, while unchecked exceptions (usually) expose programmer mistakes. Declaring a signature with throws Throwable forces callers to catch, and allows them to suppress, things which shouldn't be caught or suppressed.

    If at all possible, you should fix the ProceedingJoinPoint.proceed() method's signature, but if you don't have control over that class, your own code should wrap it in a more reasonable exception.

    How to wrap it depends on what you expect of callers of your code. If any Throwable is likely to be a condition that no one can possibly do anything to correct or address, you might as well wrap it in an unchecked RuntimeException:

    try {
        return joinPoint.proceed();
    } catch (Throwable t) {
        throw new RuntimeException(t);
    } finally {
        //some more code here
    }
    

    If you want to make sure callers handle all Throwables gracefully, you should create your own application-specific exception class:

    try {
        return joinPoint.proceed();
    } catch (Throwable t) {
        throw new JoinPointException(t);
    } finally {
        //some more code here
    }
    

    The exception class is simply:

    public class JoinPointException
    extends Exception {
        private static final long serialVersionUID = 1;
    
        public JoinPointException(Throwable cause) {
            super(cause);
        }
    
        public JoinPointException(String message,
                                  Throwable cause) {
            super(message, cause);
        }
    }