此内容没有您所选择的语言版本。
47.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 aWebApplicationException
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 thedefault.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 aWebApplicationException
exception with a custom exception mapper. For example, if this option is enabled, it would be possible to catch aWebApplicationException
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 47.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 47.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 47.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 47.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 47.7, “Registering exception mappers with the runtime” shows a JAX-RS server configured to use a custom exception mapper,
SecurityExceptionMapper
.
Example 47.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); ...