Search code examples
javaspring-mvcspring-bootmicroservicesnetflix

Java Spring-boot micro-services Exception handling


Java exception handling is sub divided in to Errors, checked exceptions and unchecked exceptions. This question is about exceptions.

Normal Java exception handling is to extend the Exception class for checked exceptions and handle those as you need by considering exception hierarchy.

E.g.:

public class ExceptionA extends Exception {}

public class RunClass {

    public static void main() {
        try {
            RunClass runClass = new RunClass();
            runClass.doSomething();
        } catch(ExceptionA eA) {
            // Do ExceptionA related resolutions.
        } catch(Exception e) {
            // Do Exception related resolutions.
        }
    }

    public doSomething() throws ExceptionA {
        throw new ExceptionA();
    }
}

But I saw major Spring books and even on the Internet tutorials mentioned with Spring-boot and in the context of micro-services always extend from RuntimeException class even with the @ControllerAdvice.

This is clear violation of Java exception handling basics. But still there is an argument saying that, it is extended with RuntimeException because of this exception is handled by @ExceptionHandler method and it is generated and handled both in runtime.

Still, because of this extension from RuntimeException makes compile time exception handling trail not visible and makes hard to trace back how exception is thrown up. Due to these reasons, I still believe, follow the basic Java checked and unchecked exception handling concept still with @ExceptionHandler method.

E.g.:

public class ExceptionRA extends RuntimeException {}

@ContollerAdvice
public class ExceptionHandler {

    @ExceptionHandler(ExceptionRA.class)
    public String handleException (Exception exception, Model model) {
        return "exception";
    }

}

@Controller
public class RunClass {

    @RequestMapping("/url1")
    public doSomething() {
        throw new ExceptionRA();
    }
}

Should I follow the extending RuntimeException for all exception scenarios with @ExcpetionHadler or follow the basic Java checked and unchecked mechanism with @ExceptionHaldler? Ideas, suggestions and corrections are welcome.


Solution

  • Preferences on checked/unchecked exceptions are like a religion.

    You normally don't call controller methods in your own code. Usually you won't have code like:

    try {
       runClass.doSomething();
    } catch(ExceptionRA exra) {
      // Handle handle handle
    }
    

    So you won't directly profit from checked exceptions throws from the controller method. They won't force any checked handling because there's nowhere to handle them. So you can just as well throw unchecked exceptions and make method signature shorter. There's no added value in throwing checked exceptions from controller methods.

    An exception can also be thrown by some busines service method that controller is calling. This rises two questions:

    • Should you use checked or unchecked exceptions in your business logic?
    • If business logic throws checked exception, should you wrap it as an unchecked exception? Or just pass through?

    The answer to the first question is - you should not let this decision be influenced by what you do in controller. Do it according to your "exception religion". If you prefer checked exception, use checked exceptions, no matter if you'd use unchecked in controller or not.

    No to the second question. Assuming your business logic throws a checked exception. If this exception would adequately represent the situation to the caller, there's no reason to wrap it into any other exception, be it checked or unchecked. If your business exception does not explain the situation correctly to the caller, better wrap it. Then, unchecked exception will make your signature shorter.

    Now a personal opinion. I generally prefer checked exceptions for everything except programming errors. I also use them in controllers (never mind somewhat longe method signatures).