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.
Exception mappers are used in two cases:
When a
WebApplicationException
, or one of its subclasses, with an empty entity body is thrown, the runtime will check to see if there is an exception mapper that handlesWebApplicationException
exceptions. If there is the exception mapper is used to create the response sent to the consumer.When any exception other than a
WebApplicationException
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.
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.
Exception mappers are created by implementing the
javax.ws.rs.ext.ExceptionMapper<E>
interface. As shown in
Example 5.5, the interface has a single method,
toResponse()
, that takes the original exception as a parameter
and returns a Response
object.
Example 5.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. Therefor they must be
decorated with the @Provder
annotation.
If an exception occurs while the exception mapper is building the Response
object, the runtime will a response with a status of 500 Server Error
to the consumer.
Example 5.6 shows an exception mapper that intercepts
Spring AccessDeniedException
exceptions and generates a response
with a 403 Forbidden
status and an empty entity body.
Example 5.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
.
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 5.7 shows a JAX-RS server configured to use a an exception mapper.
Example 5.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>