前回からの続き。
例外ハンドリング
アプリケーションからスローされた WebApplicationException およびそのサブクラスはJAX-RSのコンテナによりキャッチされ、例外に応じたレスポンスが返却されます。
レスポンスは WebApplicationException クラスの getResponse() メソッドにて生成されます。
public class WebApplicationException extends RuntimeException { public Response getResponse() { return response; } }
以下のように WebApplicationException 以外の例外がスローされた場合
@GET @Path("{id}") @Produces({MediaType.APPLICATION_JSON}) public Customer get(@PathParam("id") Long id) { Customer customer = Ebean.find(Customer.class, id); if (customer == null) throw new RuntimeException("error."); return customer; }
例外はアプリケーションサーバ側まで伝搬します。 今回の例では Grizzlyにより以下のようなレスポンス(500)が返却されることになります。

定義済み例外
JAX-RX の API では WebApplicationException のサブクラスとして以下の例外が定義されています。
| 例外 | HTTPステータス |
|---|---|
| BadRequestException | 400 |
| ForbiddenException | 403 |
| InternalServerErrorException | 500 |
| NotAcceptableException | 406 |
| NotAllowedException | 405 |
| NotAuthorizedException | 401 |
| NotFoundException | 404 |
| NotSupportedException | 415 |
| ServiceUnavailableException | 503 |
| ServerErrorException | 5XX |
| RedirectionException | 3XX |
必要に応じてこれらの例外を使うことができます。
ExceptionMapper
WebApplicationException 及びそのサブクラス以外の例外を扱いたい場合は javax.ws.rs.ext.ExceptionMapper を定義してJAX-RXコンテナに登録します。
ExceptionMapper は以下のようなインターフェース定義となっています。
public interface ExceptionMapper<E extends Throwable> { Response toResponse(E exception); }
E としてこの ExceptionMapper がハンドリングする例外を指定します。
例えば JPA の例外である javax.persistence.EntityNotFoundException をハンドリングしたい場合は以下のような ExceptionMapper を定義します。
package example.web.resource; import javax.persistence.EntityNotFoundException; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; @javax.ws.rs.ext.Provider public class EntityNotFoundExceptionMapper implements ExceptionMapper<EntityNotFoundException> { public Response toResponse(EntityNotFoundException exception) { return Response.status(Response.Status.NOT_FOUND).build(); } }
アプリケーション側で以下のように例外をスローした場合、
if (customer == null) { throw new EntityNotFoundException(); }
EntityNotFoundExceptionMapper が例外をハンドリングして以下のように 404 が返却されるようになります。

なお、main.java にて example.web.resource をリソースのスキャン対象としているため、ExceptionMapper を別パッケージに格納する場合にはスキャン対象の追加が必要となります。
public static class RsResourceConfig extends ResourceConfig { public RsResourceConfig() { packages("example.web.resource"); } }
ここまでのソースはGithubを参照してください。