Chapter 50. Handling Exceptions
Abstract
When possible, exceptions caught by a resource method should cause a useful error to be returned to the requesting consumer. JAX-RS resource methods can throw a WebApplicationException exception. You can also provide ExceptionMapper<E> implementations to map exceptions to appropriate responses.
50.1. Overview of JAX-RS Exception Classes
Overview
In JAX-RS 1.x, the only available exception class is WebApplicationException
. Since JAX-WS 2.0, however, a number of additional JAX-RS exception classes have been defined.
JAX-RS runtime level exceptions
The following exceptions are meant to be thrown by the JAX-RS runtime only (that is, you must not throw these exceptions from your application level code):
ProcessingException
-
(JAX-RS 2.0 only) The
javax.ws.rs.ProcessingException
can be thrown during request processing or during response processing in the JAX-RS runtime. For example, this error could be thrown due to errors in the filter chain or interceptor chain processing. ResponseProcessingException
-
(JAX-RS 2.0 only) The
javax.ws.rs.client.ResponseProcessingException
is a subclass ofProcessingException
, which can be thrown when errors occur in the JAX-RS runtime on the client side.
JAX-RS application level exceptions
The following exceptions are intended to be thrown (and caught) in your application level code:
WebApplicationException
-
The
javax.ws.rs.WebApplicationException
is a generic application level JAX-RS exception, which can be thrown in application code on the server side. This exception type can encapsulate a HTTP status code, an error message, and (optionally) a response message. For details, see Section 50.2, “Using WebApplicationException exceptions to report”. ClientErrorException
-
(JAX-RS 2.0 only) The
javax.ws.rs.ClientErrorException
exception class inherits fromWebApplicationException
and is used to encapsulate HTTP4xx
status codes. ServerErrorException
-
(JAX-RS 2.0 only) The
javax.ws.rs.ServerErrorException
exception class inherits fromWebApplicationException
and is used to encapsulate HTTP5xx
status codes. RedirectionException
-
(JAX-RS 2.0 only) The
javax.ws.rs.RedirectionException
exception class inherits fromWebApplicationException
and is used to encapsulate HTTP3xx
status codes.
50.2. Using WebApplicationException exceptions to report
errors indexterm:[WebApplicationException]
Overview
The JAX-RS API introduced the WebApplicationException runtime exception to provide an easy way for resource methods to create exceptions that are appropriate for RESTful clients to consume. WebApplicationException exceptions can include a Response
object that defines the entity body to return to the originator of the request. It also provides a mechanism for specifying the HTTP status code to be returned to the client if no entity body is provided.
Creating a simple exception
The easiest means of creating a WebApplicationException exception is to use either the no argument constructor or the constructor that wraps the original exception in a WebApplicationException exception. Both constructors create a WebApplicationException with an empty response.
When an exception created by either of these constructors is thrown, the runtime returns a response with an empty entity body and a status code of 500 Server Error
.
Setting the status code returned to the client
When you want to return an error code other than 500
, you can use one of the four WebApplicationException constructors that allow you to specify the status. Two of these constructors, shown in Example 50.1, “Creating a WebApplicationException with a status code”, take the return status as an integer.
Example 50.1. Creating a WebApplicationException with a status code
WebApplicationException
int
status
WebApplicationException
java.lang.Throwable
cause
int
status
The other two, shown in Example 50.2, “Creating a WebApplicationException with a status code” take the response status as an instance of Response.Status
.
Example 50.2. Creating a WebApplicationException with a status code
WebApplicationException
javax.ws.rs.core.Response.Status
status
WebApplicationException
java.lang.Throwable
cause
javax.ws.rs.core.Response.Status
status
When an exception created by either of these constructors is thrown, the runtime returns a response with an empty entity body and the specified status code.
Providing an entity body
If you want a message to be sent along with the exception, you can use one of the WebApplicationException constructors that takes a Response
object. The runtime uses the Response
object to create the response sent to the client. The entity stored in the response is mapped to the entity body of the message and the status field of the response is mapped to the HTTP status of the message.
Example 50.3, “Sending a message with an exception” shows code for returning a text message to a client containing the reason for the exception and sets the HTTP message status to 409 Conflict
.
Example 50.3. Sending a message with an exception
import javax.ws.rs.core.Response; import javax.ws.rs.WebApplicationException; import org.apache.cxf.jaxrs.impl.ResponseBuilderImpl; ... ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.status(Response.Status.CONFLICT); builder.entity("The requested resource is conflicted."); Response response = builder.build(); throw WebApplicationException(response);
Extending the generic exception
It is possible to extend the WebApplicationException exception. This would allow you to create custom exceptions and eliminate some boiler plate code.
Example 50.4, “Extending WebApplicationException” shows a new exception that creates a similar response to the code in Example 50.3, “Sending a message with an exception”.
Example 50.4. Extending WebApplicationException
public class ConflicteddException extends WebApplicationException { public ConflictedException(String message) { ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.status(Response.Status.CONFLICT); builder.entity(message); super(builder.build()); } } ... throw ConflictedException("The requested resource is conflicted.");
50.3. JAX-RS 2.0 Exception Types
Overview
JAX-RS 2.0 introduces a number of specific HTTP exception types that you can throw (and catch) in your application code (in addition to the existing WebApplicationException
exception type). These exception types can be used to wrap standard HTTP status codes, either for HTTP client errors (HTTP 4xx
status codes), or HTTP server errors (HTTP 5xx
status codes).
Exception hierarchy
Figure 50.1, “JAX-RS 2.0 Application Exception Hierarchy” shows the hierarchy of application level exceptions supported in JAX-RS 2.0.
Figure 50.1. JAX-RS 2.0 Application Exception Hierarchy
WebApplicationException class
The javax.ws.rs.WebApplicationException
exception class (which has been available since JAX-RS 1.x) is at the base of the JAX-RS 2.0 exception hierarchy, and is described in detail in Section 50.2, “Using WebApplicationException exceptions to report”.
ClientErrorException class
The javax.ws.rs.ClientErrorException
exception class is used to encapsulate HTTP client errors (HTTP 4xx
status codes). In your application code, you can throw this exception or one of its subclasses.
ServerErrorException class
The javax.ws.rs.ServerErrorException
exception class is used to encapsulate HTTP server errors (HTTP 5xx
status codes). In your application code, you can throw this exception or one of its subclasses.
RedirectionException class
The javax.ws.rs.RedirectionException
exception class is used to encapsulate HTTP request redirection (HTTP 3xx
status codes). The constructors of this class take a URI argument, which specifies the redirect location. The redirect URI is accessible through the getLocation()
method. Normally, HTTP redirection is transparent on the client side.
Client exception subclasses
You can raise the following HTTP client exceptions (HTTP 4xx
status codes) in a JAX-RS 2.0 application:
BadRequestException
- Encapsulates the 400 Bad Request HTTP error status.
ForbiddenException
- Encapsulates the 403 Forbidden HTTP error status.
NotAcceptableException
- Encapsulates the 406 Not Acceptable HTTP error status.
NotAllowedException
- Encapsulates the 405 Method Not Allowed HTTP error status.
NotAuthorizedException
Encapsulates the 401 Unauthorized HTTP error status. This exception could be raised in either of the following cases:
-
The client did not send the required credentials (in a HTTP
Authorization
header), or - The client presented the credentials, but the credentials were not valid.
-
The client did not send the required credentials (in a HTTP
NotFoundException
- Encapsulates the 404 Not Found HTTP error status.
NotSupportedException
- Encapsulates the 415 Unsupported Media Type HTTP error status.
Server exception subclasses
You can raise the following HTTP server exceptions (HTTP 5xx
status codes) in a JAX-RS 2.0 application:
InternalServerErrorException
- Encapsulates the 500 Internal Server Error HTTP error status.
ServiceUnavailableException
- Encapsulates the 503 Service Unavailable HTTP error status.
50.4. Mapping Exceptions to Responses
Overview
There are instances where throwing a WebApplicationException exception is impractical or impossible. For example, you may not want to catch all possible exceptions and then create a WebApplicationException for them. You may also want to use custom exceptions that make working with your application code easier.
To handle these cases the JAX-RS API allows you to implement a custom exception provider that generates a Response
object to send to a client. Custom exception providers are created by implementing the ExceptionMapper<E> interface. When registered with the Apache CXF runtime, the custom provider will be used whenever an exception of type E
is thrown.
How exception mappers are selected
Exception mappers are used in two cases:
- When any exception or one of its subclasses, is thrown, the runtime will check for an appropriate exception mapper. An exception mapper is selected if it handles the specific exception thrown. If there is not an exception mapper for the specific exception that was thrown, the exception mapper for the nearest superclass of the exception is selected.
By default, a WebApplicationException will be handled by the default mapper,
WebApplicationExceptionMapper
. Even if an additional custom mapper is registered, which could potentially handle a WebApplicationException exception (for example, a customRuntimeException
mapper), the custom mapper will not be used and theWebApplicationExceptionMapper
will be used instead.This behaviour can be changed, however, by setting the
default.wae.mapper.least.specific
property totrue
on aMessage
object. When this option is enabled, the defaultWebApplicationExceptionMapper
is relegated to the lowest priority, so that it becomes possible to handle a WebApplicationException exception with a custom exception mapper. For example, if this option is enabled, it would be possible to catch a WebApplicationException exception by registering a customRuntimeException
mapper. See the section called “Registering an exception mapper for WebApplicationException”.
If an exception mapper is not found for an exception, the exception is wrapped in an ServletException exception and passed onto the container runtime. The container runtime will then determine how to handle the exception.
Implementing an exception mapper
Exception mappers are created by implementing the javax.ws.rs.ext.ExceptionMapper<E> interface. As shown in Example 50.5, “Exception mapper interface”, the interface has a single method, toResponse()
, that takes the original exception as a parameter and returns a Response
object.
Example 50.5. Exception mapper interface
public interface ExceptionMapper<E extends java.lang.Throwable> { public Response toResponse(E exception); }
The Response
object created by the exception mapper is processed by the runtime just like any other Response
object. The resulting response to the consumer will contain the status, headers, and entity body encapsulated in the Response
object.
Exception mapper implementations are considered providers by the runtime. Therefore they must be decorated with the @Provider
annotation.
If an exception occurs while the exception mapper is building the Response
object, the runtime will send a response with a status of 500 Server Error
to the consumer.
Example 50.6, “Mapping an exception to a response” shows an exception mapper that intercepts Spring AccessDeniedException exceptions and generates a response with a 403 Forbidden
status and an empty entity body.
Example 50.6. Mapping an exception to a response
import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import org.springframework.security.AccessDeniedException; @Provider public class SecurityExceptionMapper implements ExceptionMapper<AccessDeniedException> { public Response toResponse(AccessDeniedException exception) { return Response.status(Response.Status.FORBIDDEN).build(); } }
The runtime will catch any AccessDeniedException exceptions and create a Response
object with no entity body and a status of 403
. The runtime will then process the Response
object as it would for a normal response. The result is that the consumer will receive an HTTP response with a status of 403
.
Registering an exception mapper
Before a JAX-RS application can use an exception mapper, the exception mapper must be registered with the runtime. Exception mappers are registered with the runtime using the jaxrs:providers
element in the application’s configuration file.
The jaxrs:providers
element is a child of the jaxrs:server
element and contains a list of bean
elements. Each bean
element defines one exception mapper.
Example 50.7, “Registering exception mappers with the runtime” shows a JAX-RS server configured to use a custom exception mapper, SecurityExceptionMapper
.
Example 50.7. Registering exception mappers with the runtime
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> </jaxrs:server> </beans>
Registering an exception mapper for WebApplicationException
Registering an exception mapper for a WebApplicationException
exception is a special case, because this exception type is automatically handled by the default WebApplicationExceptionMapper
. Normally, even when you register a custom mapper that you would expect to handle WebApplicationException
, it will continue to be handled by the default WebApplicationExceptionMapper
. To change this default behaviour, you need to set the default.wae.mapper.least.specific
property to true
.
For example, the following XML code shows how to enable the default.wae.mapper.least.specific
property on a JAX-RS endpoint:
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> <jaxrs:properties> <entry key="default.wae.mapper.least.specific" value="true"/> </jaxrs:properties> </jaxrs:server> </beans>
You can also set the default.wae.mapper.least.specific
property in an interceptor, as shown in the following example:
// Java public void handleMessage(Message message) { m.put("default.wae.mapper.least.specific", true); ...