This
article will illustrate how to implement
Exception Handling with Spring for a REST API. We’ll look at both the
recommended solution with Spring 3.2 and 4.x but also at the older options as
well.
Before
Spring 3.2, the two main approaches to handling exceptions in a Spring MVC
application were: HandlerExceptionResolver or the @ExceptionHandler annotation.
Both of these have some clear downsides.
After
3.2 we now have the new @ControllerAdvice annotation
to address the limitations of the previous two solutions.
All of
these do have one thing in common – they deal with the separation
of concerns very well. The app can throw exception normally to
indicate a failure of some kind – exceptions which will then be handled
separately.
2.
Solution 1 – The Controller level @ExceptionHandler
The
first solution works at the @Controller level – we will define
a method to handle exceptions, and annotate that with @ExceptionHandler:
This
approach has a major drawback – the @ExceptionHandler annotated
method is only active for that particular Controller, not
globally for the entire application. Of course adding this to every controller
makes it not well suited for a general exception handling mechanism.
The
limitation is often worked around by having all
Controllers extend a Base Controller class– however, this can be a
problem for applications where, for whatever reasons, the Controllers cannot be
made to extend from such a class. For example, the Controllers may already
extend from another base class which may be in another jar or not directly
modifiable, or may themselves not be directly modifiable.
Next,
we’ll look at another way to solve the exception handling problem – one that is
global and does not include any changes to existing artifacts such as
Controllers.
3.
Solution 2 – The HandlerExceptionResolver
The
second solution is to define an HandlerExceptionResolver –
this will resolve any exception thrown by the application. It will also allow
us to implement a uniform exception handling mechanism in
our REST API.
Before
going for a custom resolver, let’s go over the existing implementations.
3.1.
ExceptionHandlerExceptionResolver
This
resolver was introduced in Spring 3.1 and is enabled by default in the DispatcherServlet.
This is actually the core component of how the @ExceptionHandler mechanism
presented earlier works.
3.2.DefaultHandlerExceptionResolver
This
resolver was introduced in Spring 3.0 and is enabled by default in the DispatcherServlet.
It is used to resolve standard Spring exceptions to their corresponding HTTP
Status Codes, namely Client error – 4xx and Server error – 5xx status
codes. Here is thefull list of
the Spring Exceptions it handles, and how these are mapped to status codes.
While
it does set the Status Code of the Response properly, one limitation
is that it doesn’t set anything to the body of the Response. And
for a REST API – the Status Code is really not
enough information to present to the Client – the response has to have a body
as well, to allow the application to give additional information about the
failure.
This
can be solved by configuring View resolution and rendering error content
throughModelAndView, but the solution is clearly not optimal – which is
why a better option has been made available with Spring 3.2 – we’ll talk about
that in the latter part of this article.
3.3.ResponseStatusExceptionResolver
This
resolver was also introduced in Spring 3.0 and is enabled by default in theDispatcherServlet.
Its main responsibility is to use the @ResponseStatus annotation
available on custom exceptions and to map these exceptions to HTTP status
codes.
Same as
the DefaultHandlerExceptionResolver, this resolver is limited in
the way it deals with the body of the response – it does map the Status Code on
the response, but the body is still null.
The SimpleMappingExceptionResolver has
been around for quite some time – it comes out of the older Spring MVC model
and is not very relevant for a REST Service. It is
used to map exception class names to view names.
The AnnotationMethodHandlerExceptionResolver was
introduced in Spring 3.0 to handle exceptions through the @ExceptionHandler annotation,
but has been deprecated byExceptionHandlerExceptionResolver as
of Spring 3.2.
3.5.
CustomHandlerExceptionResolver
The
combination of DefaultHandlerExceptionResolver and ResponseStatusExceptionResolvergoes
a long way towards providing a good error handling mechanism for a Spring
RESTful Service. The downside is – as mentioned before – no
control over the body of the response.
Ideally,
we’d like to be able to output either JSON or XML, depending on what format the
client has asked for (via the Accept header).
This
alone justifies creating a new, custom exception
resolver:
One
detail to notice here is the Request itself is available, so the application
can consider the value of the Accept header sent by the
client. For example, if the client asks for application/jsonthen,
in case of an error condition, the application should still return a response
body encoded with application/json.
The
other important implementation detail is that a ModelAndView is
returned – this is the body of the response and
it will allow the application to set whatever is necessary on it.
This
approach is a consistent and easily configurable mechanism for the error
handling of a Spring REST Service. It is does however have limitations: it’s
interacting with the low levelHtttpServletResponse and it fits into
the old MVC model which uses ModelAndView – so there’s still
room for improvement.
4. New
Solution 3 – The New @ControllerAdvice (Spring 3.2 And Above)
Spring
3.2 brings support for a global @ExceptionHandler with
the new @ControllerAdviceannotation. This enables a mechanism that
breaks away from the older MVC model and makes use of ResponseEntity along
with the type safety and flexibility of @ExceptionHandler:
String bodyOfResponse = "This should be application
specific";
returnhandleExceptionInternal(ex, bodyOfResponse,
newHttpHeaders(),
HttpStatus.CONFLICT, request);
}
}
The new
annotation allows the multiple scattered @ExceptionHandler from
before to be consolidated into a single, global error
handling component.
The
actual mechanism is extremely simple but also very flexible:
it
allows full control over the body of the response as well as the status
code
it
allows mapping of several exceptions to the same method, to be handled
together
it
makes good use of the newer RESTful ResposeEntity response
One
thing to keep in mind here is to match the exceptions
declared with@ExceptionHandlerwith
the exception used as argument of the method. If these don’t match,
the compiler will not complain – no reason it should, and Spring will not
complain either.
However,
when the exception is actually thrown at runtime, the
exception resolving mechanism will fail with:
1
2
java.lang.IllegalStateException: No suitable resolver forargument [0] [type=...]
HandlerMethod details: ...
5.
Handle the Access Denied in Spring Security
The
Access Denied occurs when an authenticated user tries
to access resources that he doesn’t have enough authorities to access.
5.1.
MVC – Custom Error Page
First,
let’s look at the MVC style of solution and see how to customize an error page
for Access Denied:
This
tutorial discussed several ways to implement an exception handling mechanism
for a REST API in Spring, starting with the older mechanism and continuing with
the Spring 3.2 support and into 4.0 and 4.1.
Build Your Own Test Framework
-
[image: Build Your Own Test Framework]
Learn to write better automated tests that will dramatically increase your
productivity and have fun while doing so...
EndOfLife Software packages
-
The "End of Life" (EOL) page for Software provides information on the
release dates, support periods, and security status of different Software
versions. I...
How to Install Java on Ubuntu 24.04
-
Connect to us ( @twitter | @facebook )
Java is a versatile programming language that can be installed on Ubuntu
24.04 using different methods, such as “a...
Book Review: The Girl in White Gloves by Kerri Maher
-
[image: The Girl in White Gloves]*The Girl in White Gloves by Kerri Maher*
*Goodreads*
I was curious to learn about old Hollywood, but beyond that I wasn't ...
convert .pem file to .ppk using puttygen - AWS
-
PEM-Privacy Enhanced Mail is a Base64 encoded DER certificate file
format. PEM certificates are frequently used for web servers as they can
easily be tra...
Spring Boot Webflux DynamoDB Tutorial
-
Creating REST API in Spring Boot Webflux and AWS DynamoDB. Step by step
guide for storing retriving data in DynamoDB using Spring Boot Webflux and
exposing...
Top Developer Collaboration Tools
-
How to drive your project into a corner? Just in case you wondered, there
are multiple options. The surest one is miscommunication. Considering that
you ca...
Meet The Wattpad Stars: Brittany Geragotelis
-
After 10 years of pounding the pavement with publishers and agents,
Brittany Geragotelis decided to break free from gatekeepers by posting an
original stor...
POI Hide UnHide Rows Columns Java Example
-
In this tutorial, we will discuss how to hide / unhide rows / columns in an
Excel worksheet using Apache POI, with suitable Java Examples.We will cover
the...
OSGi - Road Ahead
-
OSGi has been introduced many times in the past few years and will still
require some in the future1. With so many introductions, one might be
inclined to ...
The Two Ways of Doing a Job
-
Whether it's deployment, development, performance tuning, troubleshooting
or something else, there are two fundamentally different ways of doing your
job: ...
Blog Members
-
Here is how to show off your blog members. These are members of your blog
community who have joined your blog through Google Friend Connect. Put all
your m...