Capture Response Payload in JAX-RS filter

codehammer picture codehammer · Aug 15, 2014 · Viewed 9.3k times · Source

I want to capture and log the response payload in JAX-RS filter. Here is the code snippet of the filter method that I'm using to intercept the response. (FYI - I'm using RestEasy for implementation)

@Override
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext         responseContext) throws IOException {
    ...
      final OutputStream out = responseContext.getEntityStream();
       try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
               out.write(baos.toByteArray());
        ....
   }
}

However, the ByteArrayOutputStream turns out be empty. Looking at the RestEasy code, it's using DeferredOutputStream, but not sure how it would matter here in pulling the response payload. I have tried writing to byte[] directly, but that doesn't help either. Am I missing anything here ? Thanks.

Answer

lefloh picture lefloh · Aug 16, 2014

If you don't want to write more data to the response you don't need to deal with the OutputStream. Just use the response entity:

@Provider
public class SomeFilter implements ContainerResponseFilter {

    private Logger LOG = LoggerFactory.getLogger(SomeFilter.class);

    @Override
    public void filter(ContainerRequestContext requestContext,
            ContainerResponseContext responseContext) throws IOException {
        LOG.info("response entity: " + responseContext.getEntity());
    }

}

The OutputStream is empty at the time the Filter is called because the JAX-RS runtime has not written to it. After your Filter the runtime will choose the correct MessageBodyWriter which will serialize the entity to the OutputStream.

You could also intercept all MessageBodyWriters with a WriterInterceptor. Following example passes a ByteArrayOutputStream to the MessageBodyWriter and restores the original OutputStream afterwards:

@Provider
public class ResponseInterceptor implements WriterInterceptor {

    private Logger LOG = LoggerFactory.getLogger(ResponseInterceptor.class);

    @Override
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
        OutputStream originalStream = context.getOutputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        context.setOutputStream(baos);
        try {
            context.proceed();
        } finally {
            LOG.info("response body: " + baos.toString("UTF-8"));
            baos.writeTo(originalStream);
            baos.close();
            context.setOutputStream(originalStream);
        }
    }

}