Jersey ...如何记录所有异常,但仍然调用ExceptionMappers

Jon*_*her 7 java rest jax-rs jersey java-ee

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

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

所以你可能在想,'嘿,这很容易,只需实现一个异常映射器并记录异常."所以我做了:

public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> {
    private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);

    /**
     * {@inheritDoc}
     */
    @Override
    public Response toResponse(Exception exception) {
        log.error("toResponse() caught exception", exception);
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Adr*_*ker 32

您可以使用RequestEventListener来侦听异常事件并记录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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ald*_*den 7

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

@Provider
public class RestExceptionMapper implements ExceptionMapper<Throwable>
{
    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();            
    }
}
Run Code Online (Sandbox Code Playgroud)

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

JAX-RS 2.0规范,第4.4章

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

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

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