JAX-RS 2 print JSON request

I would like to be able to print JAX-RS 2 JSON using a request, regardless of the actual implementation on my application server.

I tried the proposed solutions for SO, but all of them include binaries from a real implementation (e.g. Jersey, etc.) and I am only allowed to use javaee-api v 7.0 in my application.

I tried to implement ClientRequestFilter and ClientResponseFilter on my client, but they do not contain serialized objects.

Here is an example 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 is 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()); } } 
+10
java json java-ee logging jax-rs
Apr 17 '16 at 11:40
source share
1 answer

So, when trying to implement this

you need to consider a couple of things
  • For the request object, you will need to handle serialization using the framework, that is, you do not want to do something like

     @Override public void filter(ClientRequestContext requestContext) { Object entity = requestContext.getEntity(); String serialized = serializeEntity(entity); log(serialized); 

    Here you serialize it yourself, possibly using Jackson ObjectMapper or something like that. You can do it this way, but it is a bit limited in the types that it can handle. If you allow an object to serialize as it is already handled by the wireframe, the infrastructure will be able to support many more types than just JSON.

    To allow the structure to handle serialization and still be able to receive serialized data, we need to use WriterInterceptor . What we can do is set the entity's output stream to ByteArrayOutputStream , and then let the structure serialize the request object to our ByteArrayOutputStream , and then rewrite these bytes after that. Here's how the LoggingFilter Jersey LoggingFilter .

  • To answer in our filter, we need to extract data from the response stream, but we also need to make sure that the stream still has data, since it has not yet been deserialized for the client. For this, mark() and reset() stream assuming that marking is supported. If not, wrap it in a BufferedOutputStream . Again, this is how the LoggingFilter Jersey deals with this.

Below is a complete simple implementation. Most of them LoggingFilter directly from the LoggingFilter Jersey, although they are removed only for your use case. Jersey LoggingFilter records a lot of other information than just the entity. One thing I left is the encoding check. I just used hard-coded UTF-8 since the MessageUtil class used by Jersey is specific to Jersey. If you want to make the filter more universal for other encodings, you may need to study this.

 import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.logging.Logger; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.client.ClientResponseContext; import javax.ws.rs.client.ClientResponseFilter; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; @Priority(Integer.MIN_VALUE) public class EntityLoggingFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor { private static final Logger logger = Logger.getLogger(EntityLoggingFilter.class.getName()); private static final String ENTITY_STREAM_PROPERTY = "EntityLoggingFilter.entityStream"; private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private final int maxEntitySize = 1024 * 8; private void log(StringBuilder sb) { logger.info(sb.toString()); } private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) throws IOException { if (!stream.markSupported()) { stream = new BufferedInputStream(stream); } stream.mark(maxEntitySize + 1); final byte[] entity = new byte[maxEntitySize + 1]; final int entitySize = stream.read(entity); b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset)); if (entitySize > maxEntitySize) { b.append("...more..."); } b.append('\n'); stream.reset(); return stream; } @Override public void filter(ClientRequestContext requestContext) throws IOException { if (requestContext.hasEntity()) { final OutputStream stream = new LoggingStream(requestContext.getEntityStream()); requestContext.setEntityStream(stream); requestContext.setProperty(ENTITY_STREAM_PROPERTY, stream); } } @Override public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { final StringBuilder sb = new StringBuilder(); if (responseContext.hasEntity()) { responseContext.setEntityStream(logInboundEntity(sb, responseContext.getEntityStream(), DEFAULT_CHARSET)); log(sb); } } @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { final LoggingStream stream = (LoggingStream) context.getProperty(ENTITY_STREAM_PROPERTY); context.proceed(); if (stream != null) { log(stream.getStringBuilder(DEFAULT_CHARSET)); } } private class LoggingStream extends FilterOutputStream { private final StringBuilder sb = new StringBuilder(); private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); LoggingStream(OutputStream out) { super(out); } StringBuilder getStringBuilder(Charset charset) { // write entity to the builder final byte[] entity = baos.toByteArray(); sb.append(new String(entity, 0, entity.length, charset)); if (entity.length > maxEntitySize) { sb.append("...more..."); } sb.append('\n'); return sb; } @Override public void write(final int i) throws IOException { if (baos.size() <= maxEntitySize) { baos.write(i); } out.write(i); } } } 

See also:

+15
Apr 17 '16 at 14:28
source share



All Articles