I'd like to be able to print JAX-RS 2 JSON payload from request, regardless of actual implementation on my application server.
I've tried suggested solutions on SO but all include binaries from actual implementation (like Jersey and similar), and I'm allowed only to use javaee-api v 7.0 in my application.
I've tried implementing ClientRequestFilter and ClientResponseFilter on my Client but they don't contain serialized entities.
Here's an example of client:
WebTarget target = ClientBuilder.newClient().register(MyLoggingFilter.class).target("http://localhost:8080/loggingtest/resources/accounts");
Account acc = target.request().accept(MediaType.APPLICATION_JSON).get(account.Account.class);
And here's the implementation of MyLoggingFilter:
@Provider
public class MyLoggingFilter implements ClientRequestFilter, ClientResponseFilter {
private static final Logger LOGGER = Logger.getLogger(MyLoggingFilter.class.getName());
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
LOGGER.log(Level.SEVERE, "Request method: {0}", requestContext.getMethod());
}
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
LOGGER.log(Level.SEVERE, "Response status: {0}", responseContext.getStatus());
}
}
So there are a couple things to consider when trying to implement this
For the request entity, you will want the serialization to be handle by the framework, meaning you don't want to do something like
Here you are serializing it yourself, maybe using Jackson
ObjectMapper
or something. You could do it this way, but it's kind of limited in the types it can handle. If you let the object be serialized the way it is already handled by the framework, the framework will be able to support many more types than just JSON.To let the framework handle the serialization, and still be able to get serialized data, we need to use a
WriterInterceptor
. What we can do is set the entity output stream to aByteArrayOutputStream
, and then let the framework serialize the request object to ourByteArrayOutputStream
, then afterwords log those bytes. This is how the JerseyLoggingFilter
handles this.For the response, in our filter, we need to extract the data from the response stream, but also we need to make sure the stream still has data, as it has not been deserialized yet for the client. To do this
mark()
andreset()
the stream, assuming marking is supported. If not, wrap it in aBufferedOutputStream
. Again, this is how the JerseyLoggingFilter
handles this.Below is a complete simple implementation. Most of it is taken straight from the Jersey
LoggingFilter
, though it is stripped down just for your use case. The JerseyLoggingFilter
logs a lot of other information, aside from the just the entity. One thing I left out is the checking for the charset. I just used a hard coded UTF-8, as theMessageUtil
class used by Jersey, is Jersey specific. If you want to make the filter more universal for other charsets, you may want to look into fixing that.See Also:
LoggingFilter