前回からの続き。
例外ハンドリング
アプリケーションからスローされた 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を参照してください。