2016-07-19 4 views
1

У меня есть клиент REST, который создает объект XML через Entity.entity(myObject, MediaType.APPLICATION_XML_TYPE). После этого я звоню webTarget.request().buildPost(...Как получить простой XML из javax.ws.rs Entity на стороне клиента

Как я могу получить тело запроса XML, которое мой клиент отправит на сервер? (Мне нужно это для отладки причин.) Все, что я получаю здесь, это объект Entity.

Конечно, я мог бы сериализовать его сам с Marshaller, но это действительно то же самое XML клиент отправил бы?

ответ

3

Вы могли бы ClientRequestFilter как следующий, который является упрощенной версией LoggingFilter Джерси:

import java.io.ByteArrayOutputStream; 
import java.io.FilterOutputStream; 
import java.io.IOException; 
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.ConstrainedTo; 
import javax.ws.rs.RuntimeType; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.client.ClientRequestContext; 
import javax.ws.rs.client.ClientRequestFilter; 
import javax.ws.rs.container.PreMatching; 
import javax.ws.rs.ext.WriterInterceptor; 
import javax.ws.rs.ext.WriterInterceptorContext; 

@Priority(Integer.MIN_VALUE) 
@ConstrainedTo(RuntimeType.CLIENT) 
public class LoggingFilter implements ClientRequestFilter, WriterInterceptor { 

    private static final Logger LOGGER = 
            Logger.getLogger(LoggingFilter.class.getName()); 

    private static final String ENTITY_STREAM_PROPERTY = 
            LoggingFilter.class.getName() + ".entityLogger"; 

    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; 

    private static final int MAX_ENTITY_SIZE = 1024 * 8; 

    private void log(StringBuilder sb) { 
     LOGGER.info(sb.toString()); 
    } 

    @Override 
    public void filter(ClientRequestContext context) throws IOException { 

     if (context.hasEntity()) { 
      OutputStream stream = new LoggingStream(context.getEntityStream()); 
      context.setEntityStream(stream); 
      context.setProperty(ENTITY_STREAM_PROPERTY, stream); 
     } 
    } 

    @Override 
    public void aroundWriteTo(WriterInterceptorContext context) 
       throws IOException, WebApplicationException { 

     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 b = new StringBuilder(); 
     private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

     LoggingStream(final OutputStream inner) { 
      super(inner); 
     } 

     StringBuilder getStringBuilder(final Charset charset) { 
      // write entity to the builder 
      final byte[] entity = baos.toByteArray(); 

      b.append(new String(entity, 0, 
           Math.min(entity.length, MAX_ENTITY_SIZE), charset)); 
      if (entity.length > MAX_ENTITY_SIZE) { 
       b.append("...more..."); 
      } 
      b.append('\n'); 

      return b; 
     } 

     @Override 
     public void write(final int i) throws IOException { 
      if (baos.size() <= MAX_ENTITY_SIZE) { 
       baos.write(i); 
      } 
      out.write(i); 
     } 
    } 
} 

И зарегистрировать его в Client:

Client client = ClientBuilder.newClient().register(LoggingFilter.class); 
+1

Спасибо за подробный ответ! – Sebastian

+1

+1 за отличный ответ, это мне очень помогло. У меня только один маленький вопрос: как бы вы адаптировали это для регистрации ответа вместо запроса? Когда я меняю его на реализацию ClientResponseFilter и меняю контекст фильтра на объект контекста ответа, я получаю InputStream вместо OutputStream, и я не могу понять, как двигаться вперед с ним в этой точке. – Tim

+1

Спасибо за подробный код, отлично подходит для меня. Добавлены некоторые дополнительные настройки для нашей конфигурации ведения журнала. – kdoteu