The Guestbook sample demonstrates some scenarios for the handling of bad conditions, exceptions, and errors.
The sample is based on early Internet guestbooks where visitors leave new comments, update or delete old comments, or retrieve a list of comments. The comments are stored in an in-memory data store.
This sample is only for illustrative purposes and is not intended to be a starting point for a real guestbook.
HTTP Method | URI | Input Type(s) | Output Type(s) | Note(s) |
---|---|---|---|---|
GET | /guestbook/{id} | n/a | text/xml | Sets HTTP status code |
POST | /guestbook | text/xml | text/xml | Throws javax.ws.rs.WebApplicationException |
DELETE | /guestbook/{id} | n/a | n/a | Throws RuntimeException |
PUT | /guestbook/{id} | text/xml | text/xml | Throws checked exception |
Most RESTful web services use standard HTTP status codes to some degree. You can set the status code in a javax.ws.rs.core.Response by calling its status method.
A simple HTTP GET method for retrieving a new message is displayed below. In the code example below, an infamous HTTP 404 status code is set if the comment with a given message ID does not exist. A normal HTTP 200 OK status and response entity are set if the message is found using one of Response's convienence methods.
|
Before talking about regular Java exceptions and errors, JAX-RS introduces the javax.ws.rs.WebApplicationException. It provides an easy way to throw an exception with a status code or a whole javax.ws.rs.core.Response. The status code or Response can be used by the runtime to construct a more usable end-user response. WebApplicationException is useful when you want to give a custom response but do not want to add a new checked exception to your method signature.
A HTTP POST method for creating a new message is given below.
A HTTP 400 status code is set if the POST requester did not send a comment to store via a WebApplicationException.
If an ID, message, or an author are not set in the comment request data, then a custom HTTP 400 status Response with an entity is constructed. The Response is then passed to a WebApplicationException which itself is thrown. By default, the JAX-RS runtime will use the Response to return the client response.
|
In a real application, you cannot wrap every exception in a WebApplicationException. In JAX-RS, runtime exceptions and errors propagate to the container. Checked exceptions and other throwables are wrapped in a container specific exception, and then the container exception is thrown. By allowing the exceptions to be thrown to the container, then the container's regular exception handling is used (e.g. servlet error pages).
Here is a HTTP DELETE resource method that shows a possible runtime exception:
|
In the above snippet, if the path parameter "commentId" is not an integer, then a NumberFormatException is thrown from Integer.valueOf(). The runtime exception would be thrown to the container.
Here is a HTTP PUT method that shows a possible checked exception:
|
GuestbookException is an application defined checked Java exception. There are many conditions where it is thrown. If the checked exception is thrown, then it is wrapped in a container-specific exception (such as a ServletException) and then re-thrown to the container.
Allowing exceptions to be thrown to the container may be all you need but sometimes you may want to give a custom response. In the above HTTP PUT method, the request data could not include the Comment. The aComment.getId() call would result in a NullPointerException if "aComment" is null.
An javax.ws.rs.ext.ExceptionMapper<T> allows the JAX-RS runtime to catch any java.lang.Throwable and map it to a JAX-RS Response. You could do additional tasks as well such as logging the exception in the ExceptionMapper.
Here is an example of an ExceptionMapper for NullPointerException:
|
Whenever a NullPointerException is thrown, the JAX-RS runtime will use the above ExceptionMapper to create a Response. The Response would then be used in normal processing.
To create an ExceptionMapper:
ExceptionMappers are chosen based on the generic type T. The closest matching ExceptionMapper type to the thrown exception type is used.
For instance, suppose there were separate ExceptionMapper<RuntimeException> and an ExceptionMapper<NullPointerException> providers. If a NullPointerException or any of its subclasses was thrown in the application, the ExceptionMapper<NullPointerException> would be used. If any other RuntimeException is thrown, the ExceptionMapper<RuntimeException> would be used.