Download capture payload to JAX-RS filter

I want to capture and register the response payload in a JAX-RS filter. Here is the code snippet of the filter method that I use to intercept the response. (FYI - I use RestEasy to implement)

@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, ByteArrayOutputStream is empty. Looking at the RestEasy code, it uses a DeferredOutputStream, but is not sure how it matters here when pulling the response payload. I tried writing byte [] directly, but that doesn't help either. Did I miss something? Thanks.

+6
source share
2 answers

If you do not want to write more data in response, you do not need to deal with OutputStream. Just use the response object:

 @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 output stream is empty during the filter call because the JAX-RS runtime is not recorded. After your filter, the runtime will select the correct MessageBodyWriter , which will serialize the object into an OutputStream.

You can also intercept all MessageBodyWriters with WriterInterceptor . The following example passes the ByteArrayOutputStream to MessageBodyWriter and then restores the original OutputStream:

 @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); } } } 
+16
source

I had the same problem and was solved differently, so I leave my answer here, although the question is already marked as answered correctly.

I implemented a ContainerResponseFilter and introduced Providers through which I received a MessageBodyWriter for a specific response entity and a specific MediaType ; then I used it to write the object to an accessible OutputStream , which I used to register the object.

This approach allows you to capture the exact payload of the response, and not just the object attached to the Response , that is, if the object is serialized as JSON, then you will write JSON, if it is serialized as XML, you will register XML. If using the toString() method of an attached object is enough, this approach is just a useless computational cost.

Here is the code (the trick is done in the CustomResponseLogger.payloadMessage function):

 @Provider public class CustomResponseLogger implements ContainerResponseFilter { private static final Logger LOGGER = LoggerFactory.getLogger(CustomResponseLogger.class); @Context private Providers providers; @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { String message = new String("Outgoing message").concat(System.lineSeparator()); if (responseContext.getMediaType() != null) message = message.concat("Content-Type: ").concat(responseContext.getMediaType().toString()).concat(System.lineSeparator()); message = message.concat("Payload: ").concat(payloadMessage(responseContext)).concat(System.lineSeparator()); LOGGER.info(message); } private String payloadMessage(ContainerResponseContext responseContext) throws IOException { String message = new String(); if (responseContext.hasEntity()) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Class<?> entityClass = responseContext.getEntityClass(); Type entityType = responseContext.getEntityType(); Annotation[] entityAnnotations = responseContext.getEntityAnnotations(); MediaType mediaType = responseContext.getMediaType(); @SuppressWarnings("unchecked") MessageBodyWriter<Object> bodyWriter = (MessageBodyWriter<Object>) providers.getMessageBodyWriter(entityClass, entityType, entityAnnotations, mediaType); // I retrieve the bodywriter bodyWriter.writeTo(responseContext.getEntity(), entityClass, entityType, entityAnnotations, mediaType, responseContext.getHeaders(), baos); // I use the bodywriter to write to an accessible outputStream message = message.concat(new String(baos.toByteArray())); // I convert the stream to a String } return message; } } 

Hope this helps!

+1
source

Source: https://habr.com/ru/post/973874/


All Articles