Jersey …如何记录所有exception,但仍然调用ExceptionMappers

我有点束缚……想要我的蛋糕,也吃它。

我想记录我的应用程序抛出的所有exception。 因此,如果有人遇到错误的URL,我想将堆栈跟踪记录到SLF4J。

所以你可能在想,“嘿,这很简单,只需实现exception映射并记录exception。”所以我做了:

public class RestExceptionMapper implements ExceptionMapper { private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class); /** * {@inheritDoc} */ @Override public Response toResponse(Exception exception) { log.error("toResponse() caught exception", exception); return null; } } 

如果你这样做,当有人输入错误的URL时,而不是404错误,他们会得到500错误。 有人会猜测返回null会将exception传播到链式处理程序,但Jersey不会这样做。 它实际上提供了很少的信息,为什么它会选择一个处理程序而不是另

有没有人遇到过这个问题,你是怎么解决的?

要返回正确的http状态代码,您的exception映射器可能如下所示:

 @Provider public class RestExceptionMapper implements ExceptionMapper { private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class); @Override public Response toResponse(Throwable exception) { log.error("toResponse() caught exception", exception); return Response.status(getStatusCode(exception)) .entity(getEntity(exception)) .build(); } /* * Get appropriate HTTP status code for an exception. */ private int getStatusCode(Throwable exception) { if (exception instanceof WebApplicationException) { return ((WebApplicationException)exception).getResponse().getStatus(); } return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); } /* * Get response body for an exception. */ private Object getEntity(Throwable exception) { // return stack trace for debugging (probably don't want this in prod...) StringWriter errorMsg = new StringWriter(); exception.printStackTrace(new PrintWriter(errorMsg)); return errorMsg.toString(); } } 

此外,您似乎对级联exception映射器感兴趣,但根据规范,这是不可能的:

JAX-RS 2.0规范,第4.4章

“exception映射提供程序将已检查或运行时exception映射到Response实例。exception映射提供程序实现ExceptionMapper接口,并且可以使用@Provider进行注释以进行自动发现。当选择exception映射提供程序来映射exception时,实现必须使用generics类型是exception的最近超类的提供者。

当资源类或提供程序方法抛出具有exception映射提供程序的exception时,匹配的提供程序用于获取Response实例。 生成的响应将被处理,就像Web资源方法已返回响应一样,请参阅第3.3.3节。 特别是,必须使用第6章中定义的ContainerResponsefilter链处理映射的响应。

为避免可能无限循环,必须在处理请求及其相应响应期间使用单个exception映射器。 JAX-RS实现绝不能尝试映射在处理先前从exception映射的响应时抛出的exception。 相反,必须按照第3.3.4节中的步骤3和4所述处理此exception。“

您可以使用RequestEventListener来侦听exception事件并记录throwable,而不会干扰任何现有的处理。 请注意,这意味着首先注册一个ApplicationEventListener ,然后返回一个RequestEventListener实例。

 public class ExceptionLogger implements ApplicationEventListener, RequestEventListener { private static final Logger log = LoggerFactory.getLogger(RequestExceptionLogger.class); @Override public void onEvent(final ApplicationEvent applicationEvent) { } @Override public RequestEventListener onRequest(final RequestEvent requestEvent) { return this; } @Override public void onEvent(RequestEvent paramRequestEvent) { if(paramRequestEvent.getType() == Type.ON_EXCEPTION) { log.error("", paramRequestEvent.getException()); } } }