2016-04-17 11 views
10

アプリケーションサーバーの実際の実装に関係なく、リクエストからJAX-RS 2 JSONペイロードを印刷することができます。JAX-RS 2 JSONリクエストを印刷

私はSOの提案されたソリューションを試しましたが、実際にはJerseyなどのような実際の実装のバイナリがすべて含まれています。私のアプリケーションではjavaee-api v 7.0しか使用できません。

クライアントでClientRequestFilterとClientResponseFilterを実装しようとしましたが、シリアル化されたエンティティは含まれていません。

ここでは、クライアントの一例です:

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); 

そして、ここでは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()); 
    }   
} 

答えて

15

この

  1. を実装しようとしているときに考慮すべきカップルの事があります

    リクエストエンティティの場合、シリアライゼーションはフレームワークによって処理されることが必要です。ここで

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

    あなたは多分ジャクソンObjectMapperか何かを使用して、それを自分でシリアル化されているような何かをしたくないグラムあなたがになりますが、扱うことのできる種類が限られています。オブジェクトが既にフレームワークによって処理されているように直列化されるようにすると、フレームワークはJSON以外の多くの型をサポートすることができます。

    フレームワークがシリアル化を処理し、シリアル化されたデータを取得できるようにするには、WriterInterceptorを使用する必要があります。エンティティの出力ストリームをByteArrayOutputStreamに設定し、フレームワークに要求オブジェクトをByteArrayOutputStreamにシリアル化させ、その後それらのバイトをログに記録させることができます。これはジャージーLoggingFilterがこれをどのように処理するかです。応答のために

  2. は、私たちのフィルタでは、我々は、応答ストリームからデータを抽出する必要がありますが、または、我々はそれがクライアントのためにまだ直列化復元されていないとして、ストリームはまだデータを持っていることを確認する必要があります。これを行うには、ストリームがmark()reset()で、マーキングがサポートされていると仮定します。そうでない場合は、BufferedOutputStreamにラップしてください。再び、これはジャージーLoggingFilterがこれをどのように処理するかです。

以下は完全な単純な実装です。そのほとんどはジャージーLoggingFilterから直接取られていますが、ユースケースのためだけに削除されています。ジャージーLoggingFilterは、エンティティだけでなく、多くの他の情報を記録します。私が取り残したことの1つは、文字セットのチェックです。私はハードコーディングされたUTF-8を使用しました.Jerseyが使用するMessageUtilクラスがJersey固有のものです。他の文字セットに対してフィルタをより普遍的なものにしたい場合は、それを修正することができます。

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); 
     } 
    } 
} 

参照:

素晴らしい作品
+0

。私はちょうど@Providerとしてフィルタに注釈をつけ、クライアントに登録し、POSTされたエンティティからJSONを記録する必要がありました。 ところで、私はJAX-Bを使ってエンティティをシリアライズしています。あなたの時間のおかげでおかげで、私のupvoteと受け入れてください。 – D00de

+0

デバッグに最適! –