Exception handling in JAX-RS
Exception handling in JAX-RS
Reporting errors using ResponseBuilder
The Response instance can hold metadata, such as the HTTP status code, along with the entity body. The REST resource method can return the Response object to report back on the status of the REST API call to the caller.
For example, the following resource method returns HTTP 404 Not Found (represented by the following Enum constant: Response.Status.NOT_FOUND) if the department entity object is not found in the data store:
Although the approach of using the Response object for reporting errors back to the caller works for basic use cases, it may not really scale up in real life. With this approach, every resource method in a class should have the Response object as the return type. Furthermore, developers may need to catch all exceptions in the resource method and convert them to the Response object programmatically. This may eventually result in repetitive coding, silly coding errors, and maintenance issues. JAX-RS addresses this issue by allowing you to directly throw exceptions from the REST resource methods to report errors back to the caller.
Reporting errors using WebApplicationException
The JAX-RS framework provides javax.ws.rs.WebApplicationException which you can throw from the JAX-RS resource methods or provider implementations to report exceptions back to the caller. Later, in the request processing cycle, the default exception mapper class deployed by the JAX-RS runtime will intercept the exception thrown by the method and will generate an appropriate HTTP response object. WebApplicationException can be created by wrapping the response content, error text, or HTTP status code. As WebApplicationException is extended from RuntimeException, the methods that throw this exception do not need to have the throws clause for WebApplicationException in the method signature. When a method throws WebApplicationException, the server stops the execution of the request and sends the response created from WebApplicationException back to the client. Here is an example:
The preceding example throws WebApplicationException with the HTTP status 404 Not Found if the department is not found in the data store. You can use different HTTP status codes, depending upon the use case. The javax.ws.rs.core.Response.Status class holds the commonly used status codes defined by HTTP. We discussed the HTTP status codes and their meaning in the HTTP status codes section in Chapter 1, Introducing the REST Architectural Style.
There are many exceptions available in JAX-RS, subclassed from javax.ws.rs.WebApplicationException. You can use the most appropriate one in your use case. Some of the exceptions extended from WebApplicationException are as follows: BadRequestException, ForbiddenException, NotAcceptableException, NotAllowedException, NotAuthorizedException, NotFoundException, NotSupportedException, RedirectionException, InternalServerErrorException, and ServiceUnavailableException.
You can also extend WebApplicationException to hold more meaningful error messages for your application, as shown in the following code:
WebApplicationException is subclassed from RuntimeException. This fits well for handling unexpected exceptions that may occur in the REST API implementation. However, for a typical business application, there may be many modules and certain modules may be reused in a non-REST context as well. So, you cannot live with WebApplicationException (which is automatically handled by the JAX-RS runtime) for all scenarios. The next section discusses the usage of the checked business exception in the JAX-RS application.
Reporting errors using application exceptions
It is recommended to use a checked application exception for recoverable error scenarios. In this section, we will see how a checked exception can be used in a RESTful web API implementation.
Here is a checked business exception definition for use in the JAX-RS resource method:
The following code snippet uses DeprtmentNotFoundBusinessException for reporting the DepartmentNotFound error to the caller:
The preceding implementation is simple and easy to follow. However, you may want to perform an additional step to map exceptions to the HTTP response body content. Note that the JAX-RS runtime, by default, does not know how to generate the right response content for the custom application exception thrown by a method. All the unhandled exceptions are handled by the underlying servlet container, which may wrap or swallow your application exception. The solution is to use the exception mapper feature offered by JAX-RS. JAX-RS allows you to deploy a custom exception mapper implementation, which will map the business exception to the appropriate response message. The next section discusses this topic in detail.
Mapping exceptions to a response message using ExceptionMapper
You can use the javax.ws.rs.ext.ExceptionMapper class to map the checked or unchecked exceptions to the appropriate HTTP response content. At runtime, when an exception is thrown by a method, the JAX-RS runtime will scan through all registered exception mappers to find the best match for handling the exception. If there is no exact match found, runtime considers a mapper class that matches with the parent class of the checked exception class. After identifying the exception mapper class for handling an exception, the framework invokes the toResponse() method on the exception mapper instance to generate the appropriate HTTP response content for the exception.
Here is an example for the ExceptionMapper class, which creates the HTTP response for DepartmentNotFoundBusinessException:
When the runtime fails to find an exception mapper for the custom exceptions, the exception will be propagated to the underlying container, which will eventually result in javax.servlet.ServletException, sending the HTTP 500 status back to the client.
Comments
Post a Comment