JSON・XMLを返すけどエラー時はステータスコードやメッセージを選びたい

JAX-RSで200とか404とか返すだけなら、メソッド戻り値にResponseを指定してResponseを操作すればいい。

@RequestScoped
@Path("myresource")
public class MyResource {
    @GET
    public Response getIt() {
        return Response.ok().build();    // 200が返る
    }
}

JSONとかXMLとか返したいなら、戻り値にオブジェクトを指定して@ProducesでMIME(MediaType)を指定する。

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public User getIt() {
        User user = userService.getUser(1);
        return user;    // JSONが返る
    }


本題。
通常はJSONXMLを返したいけど、データベースなどにデータが無い場合は404にしたい。
参考:Chapter 7. Representations and Responses

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public User getIt() {
        try {
            User user = userService.getUser(1);
            return user;    // JSONが返る(ステータスコード:200)
        } catch (NoResultException e) {
            throw new WebApplicationException(404);    // 404が返る
        }
    }

WebApplicationExceptionをthrowする。ステータスコード返すだけならコード番号を渡す。
メッセージも変えたいならResponseを渡す。

throw new WebApplicationException(
    Response.status(Status.NOT_FOUND).entity("error. error. error.").build()
);


長すぎるし。。。
多分、WebApplicationExceptionを継承したクラス作るほうが幸せになれる。

public class CustomException extends WebApplicationException {
    public CustomException() {
        super(Response.status(Status.NOT_FOUND).build());
    }

    public CustomException(String message) {
        this(Status.NOT_FOUND, message);
    }

    public CustomException(Status status, String message) {
        this(status.getStatusCode(), message);
    }

    public CustomException(int code, String message) {
        super(
            Response.status(code).entity(message).build()
        );
    }
}

他にもExceptionMapperを使ってExceptionとレスポンスをマッピングさせる方法もある。
NoResultException -> 404 とかやってもいいけど、エラーの切り分けが面倒になりそう
(データが無いのか、単純にパスが間違っているのか、etc...)
なのでやめておく。


余談
このままだとtext/plainだけど、JSON(XML)返すサービスならエラーもJSON(XML)で返すべき?
まあMediaType指定するだけでいいから何とでもなるんだけど。