Jersey/JAX-RS异常映射器和继承

3
我正在使用Jersey/JAX-RS来实现一个RESTful Web服务。我有一个关于 ExceptionMapper 接口的问题,但它似乎没有被记录在任何地方。
假设我有以下自定义(扩展RuntimeException)异常:
  • FizzException extends RuntimeException
  • BuzzException extends FizzException
如果我希望我的异常映射器执行以下 Exception -to- Response 映射:
  • FizzException 实际上映射到 HTTP 404 NOT FOUND
  • BuzzException 映射到 HTTP 403 UNAUTHORIZED
  • 其他情况都映射到 HTTP 500 INTERNAL SERVER ERROR
所以,如果我正确理解API,我需要实现三个不同的异常映射器:
@Provider
public class DefaultExceptionMapper implements ExceptionMapper<Exception> {
    @Override
    Response toResponse(Exception exc) {
        // Map to HTTP 500
    }
}

@Provider
public class FizzExceptionMapper implements ExceptionMapper<FizzException> {
    @Override
    Response toResponse(Exception exc) {
        // Map to HTTP 404
    }
}

@Provider
public class BuzzExceptionMapper implements ExceptionMapper<BuzzException> {
    @Override
    Response toResponse(Exception exc) {
        // Map to HTTP 403
    }
}

然而,这让我很好奇:由于我们有异常类继承,哪些映射器实际上会触发?例如:
- BuzzException 扩展 FizzException,FizzException 最终扩展 Exception。那么,如果抛出 BuzzException,哪个映射器将触发:BuzzExceptionMapper、FizzExceptionMapper 还是 DefaultExceptionMapper? - 反过来:当抛出一个 Exception 时,由于 BuzzException 最终也是 Exception,哪个映射器将触发:BuzzExceptionMapper、FizzExceptionMapper 还是 DefaultExceptionMapper?

一头牛是一种动物。所以,如果你拿一头牛,但称它为“一种动物”,然后将其从山上扔下去,你扔下山的是什么?最终还是一头牛。同样地,如果你抛出一个BuzzException,那就是你从山上扔出去的东西 - 即使你称它为FizzException。 - Gimby
谢谢@Gimby。我有点理解您的比喻,但仍然可以看到一种情况,即BuzzExceptionMapp认为BuzzException是一个Exception,因此映射抛出的Exception,这是我的问题基础。但似乎Jersey已经足够聪明地进行必要的类检查,所以不用担心 :-) - IAmYourFaja
所以,如果我正确理解API,我需要实现3个不同的异常映射器——你不一定要这么做 :-) 在你的FizzExceptionMapper中,你可以检查if (e.getClass() == BuzzException.class)。另外,只是一个FYI,将您的异常类扩展为WebApplicationException并在构造函数中映射响应也是非常常见的,如此处所示。默认的Jersey映射器会处理它。 我们不需要创建自己的映射器。除非这个异常类已经存在,那么你就需要用到映射器。 - Paul Samsotha
1个回答

5

最具体的异常映射器将被调用。

所以在您的情况下:

  • BuzzException 将由 BuzzExceptionMapper 映射
  • FizzException 将由 FizzExceptionMapper 映射
  • 其他的 Exception 将由 DefaultExceptionMapper 映射

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接