例外のマッピング

【前提条件】

[環境]

【概要】

JAX-RSで例外のマッピングの方法についてです。

特定の例外をキャッチした場合、
今まではFilterで行うことが多かったのですが、
JAX-RSでは例外をマッピングして処理を行う機能がついています。

javax.ws.rs.ext.ExceptionMapperインターフェイスを使用すると
例外と処理のマッピングが行えます。

【サンプルコード(例外クラス)】

今回、サンプルでは
独自に作成した例外クラスを使用します。

RuntimeExceptionを継承したTestParentExceptionクラスと
TestParentExceptionを継承したTestChildExceptionクラスを使用します。

package jp.glory.common.exception;

public class TestParentException extends RuntimeException {

}
package jp.glory.common.exception;

public class TestChildException extends RuntimeException {

}

【サンプルコード(ExceptionMapper)】

ExceptionMapperはマッピングする例外ごとにクラスを作成します。
継承関係があったとしても指定したクラスのみをマッピングします。

今回のサンプルでは
TestParentExceptionクラスがスローされた場合は406エラー、
TestChildExceptionクラスがスローされた場合は409エラー
をレスポンスとして返すようにします。

package jp.glory.common.mapper;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import jp.glory.common.exception.TestParentException;

@Provider
public class TestParentMapper implements ExceptionMapper<TestParentException> {

    @Override
    public Response toResponse(final TestParentException exception) {

        return Response.status(Status.NOT_ACCEPTABLE).build();
    }

}
package jp.glory.common.mapper;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import jp.glory.common.exception.TestChildException;

@Provider
public class TestChildMapper implements ExceptionMapper<TestChildException> {

    @Override
    public Response toResponse(final TestChildException exception) {

        return Response.status(Status.CONFLICT).build();
    }

}

ExceptionMapperを使用する場合は
ExceptionMapperインターフェイスをimplementsします。

ExceptionMapperインターフェイスには型パラメータとして、
マッピングしたい例外クラスを指定します。
型パラメータにはThrowableのサブクラスを指定します。

作成したクラスにはjavax.ws.rs.ext.Providerアノテーションをつけます。

【サンプルコード(リソースクラス)】

リソースクラスはパスパラメータで受け取った値によって
投げる例外を分けています。

package jp.glory.ui.service;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

import jp.glory.common.exception.TestChildException;
import jp.glory.common.exception.TestParentException;

@Path("exception/{param}")
public class ExceptionMapperService {

    @GET
    public Response parseParam(@PathParam("param") final String param) {

        if ("1".equals(param)) {

            throw new TestParentException();
        }

        if ("2".equals(param)) {

            throw new TestChildException();
        }

        return Response.ok("Not error param.").build();
    }
}

ブラウザからURLを入力するとパラメータに応じて、
エラー画面が表示されます。
表示されるエラー画面のステータスコード
ExceptionMapperで返却しているステータスコードになります。

【まとめ】

JAX-RSでの例外マッピング
クラス作成とアノテーションの指定のみで簡単にできるようになっています。

作成したクラスはExceptionMapperをimplementsしているだけなので、
ユニットテストも簡単にできるようになっています。