JAX-RS 异常映射器:包装异常和默认情况怎么样?

Ale*_*ühl 3 java exception-handling jax-rs jakarta-ee

在 REST 服务中处理异常的一种典型方法是定义自定义异常类型(通常来自RuntimeException),然后实现一个映射器类来生成 HTTP 代码,例如:

public class MyExceptionMapper implements ExceptionMapper<MyException> {
  @Override
  public Response toResponse(MyExceptionex) {
    return Response.status(400).entity("bad request")
      .type(MediaType.APPLICATION_JSON).build();
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我有两个问题:

  • 我将如何为“默认情况”实现映射器,这意味着对于此处或另一个映射器中未映射的每个异常?例如,当Throwable为了生成 HTTP 500 而实现一个 for时,它不会再次捕获我自己的异常吗?或者可以定义映射器工作的顺序?
  • 当从 REST 服务调用 EJB 等托管组件时,在那里抛出的异常不会导致我自己的一个EJBException或一些Transaction...Exception包裹?

Nik*_*los 6

“默认情况”的映射器...

正如 Paul Samsotha 在评论中所写,JAX-RS 服务器运行时应该选择最具体的异常映射器。或者引用 JAX-RS 规范(适用于 JEE7/2.0 版):

3.3.4 例外

[...]

  1. 如果异常映射提供者(参见第 4.4 节)可用于异常或其超类之一,则实现必须使用其泛型类型是异常的最近超类的提供者来创建一个 Response 实例,然后根据第 3.3 节进行处理.3.[...]

所以我想你可以使用异常映射器Throwable- 它的签名无论如何都会验证它:

public interface ExceptionMapper<E extends Throwable> {...}
Run Code Online (Sandbox Code Playgroud)

从 REST 服务调用 EJB 等托管组件时...

如果需要包装异常,EJB 容器将包装异常。并非所有由 EJB 抛出的异常都需要包装。EJB 规范 (v3.1) 区分了应用程序异常(用 注释javax.ejb.ApplicationException)和“所有其他异常”(参见第 14.3 节)。因此,例外@ApplicationException并为其提供映射器。但是如果您仍然想根据包装的异常进行响应:

根据包装的异常进行响应

您不能根据包装的异常直接选择映射器。但是你可以创建用于一个异常映射器包装纸异常解开它并选择用于适当的映射器包裹基于所述异常Providers上下文(参见JAX-RS 2.0部分9.2.6和javax.ws.rs.ext.Providers的Javadocs)。例如,假设的未经测试的代码MyWrapperException是:

@Provider
public class MyWrapperExceptionMapper implements ExceptionMapper<MyWrapperException> {
    @Context
    private Providers providers;

    public Response toResponse(MyWrapperException e) {
        Throwable t = e.getCause();
        ExceptionMapper mapper = providers.getExceptionMapper(t.getClass());
        if( mapper != null ) {
            return mapper.toResponse(t);
        }
        else {
            // custom handling...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)