Error Handling with ResponseStatusException class

JPG :

All of the controllers on my projects extend from one Base controller that uses the @ExceptionHandler annotation. Seeing as what I'm currently using is a bit older than the new way to handle exceptions that spring introduced I'm trying to update my project by replacing my ExceptionHandler annotations with the most recent ResponseStatusException class.

Any tips on how to do that properly?

Pratik Malani :

Before we delve into ResponseStatusException, let’s quickly take a look at the @ResponseStatus annotation. This annotation was introduced in Spring 3 for applying HTTP Status code to an HTTP response.

We can use the @ResponseStatus annotation to set the status and reason in our HTTP response:

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found")
public class ActorNotFoundException extends Exception {
    // ...
}

If this exception is thrown while processing an HTTP request, then the response will include the HTTP status specified in this annotation.

One drawback of the @ResponseStatus approach is that it creates tight coupling with the exception. In our example, all exceptions of type ActorNotFoundException will generate the same error message and status code in the response.

ResponseStatusException

ResponseStatusException is a programmatic alternative to @ResponseStatus and is the base class for exceptions used for applying a status code to an HTTP response. It’s a RuntimeException and hence not required to be explicitly added in a method signature.

Spring provides 3 constructors to generate ResponseStatusException:

ResponseStatusException(HttpStatus status)
ResponseStatusException(HttpStatus status, java.lang.String reason)
ResponseStatusException(
  HttpStatus status, 
  java.lang.String reason, 
  java.lang.Throwable cause
)

ResponseStatusException, constructor arguments:

  • status – an HTTP status set to HTTP response
  • reason – a message explaining the exception set to HTTP response
  • cause – a Throwable cause of the ResponseStatusException

Note: in Spring, HandlerExceptionResolver intercepts and processes any exception raised and not handled by a Controller.

One of these handlers, ResponseStatusExceptionResolver, looks for any ResponseStatusException or uncaught exceptions annotated by @ResponseStatus and then extracts the HTTP Status code & reason and includes them in the HTTP response.

ResponseStatusException Benefits

ResponseStatusException usage has few benefits:

  • Firstly, exceptions of the same type can be processed separately and different status codes can be set on the response, reducing tight coupling
  • Secondly, it avoids creation of unnecessary additional exception classes
  • Finally, it provides more control over exception handling, as the exceptions can be created programmatically

Spring 5 introduced the ResponseStatusException class. We can create an instance of it providing an HttpStatus and optionally a reason and a cause:

@GetMapping("/actor/{id}")
public String getActorName(@PathVariable("id") int id) {
    try {
        return actorService.getActor(id);
    } catch (ActorNotFoundException ex) {
        throw new ResponseStatusException(
        HttpStatus.NOT_FOUND, "Actor Not Found", ex);
    }
}

What are the benefits of using ResponseStatusException?

  • Excellent for prototyping: We can implement a basic solution quite fast
  • One type, multiple status codes: One exception type can lead to multiple different responses. This reduces tight coupling compared to the @ExceptionHandler
  • We won’t have to create as many custom exception classes
  • More control over exception handling since the exceptions can be created programmatically

And what about the tradeoffs?

  • There’s no unified way of exception handling: It’s more difficult to enforce some application-wide conventions, as opposed to @ControllerAdvice which provides a global approach
  • Code duplication: We may find ourselves replicating code in multiple controllers

We should also note that it’s possible to combine different approaches within one application.

For example, we can implement a @ControllerAdvice globally, but also ResponseStatusExceptions locally. However, we need to be careful: If the same exception can be handled in multiple ways, we may notice some surprising behavior. A possible convention is to handle one specific kind of exception always in one way.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=82521&siteId=1