2013-12-16 1 views
4

Недавно я перешел от использования Джерси к CXF для приложения JAX-RS. Я также использовал StreamingOutput для вывода собственного потока, поскольку данные, содержащиеся в потоке, занимают ~ 20 секунд для создания и могут частично обрабатываться клиентами. Все это прекрасно работало с Джерси, но теперь я переключился на возвращение бобов JAXB с CXF и не могу получить потоковое поведение. С Джерси я должен был установить jersey.config.contentLength.buffer.server в 0 и сбросить OutputStream, чтобы получить данные клиенту, но я не могу найти эквивалент с CXF. Я пробовал написать Interceptor на основе примера StreamInterceptor, но метод writeMessageOutputStream не вызывается, пока вся обработка не завершится. Компонент JAXB содержит Collection с пользовательским Iterator, который поставляет данные, когда он доступен. Я вижу, как данные буферизуются в отладчике.Небуферизованный CXF (нет заголовка длины содержимого)

Как я могу передать фасоль JAXB с CXF?

ответ

3

Мне удалось сделать это с помощью Jackson и моего собственного MessageBodyWriter, BeanSerializerModifier и JsonSerializer. Мне все еще нужно найти способ с XML.

import com.fasterxml.jackson.core.JsonGenerator; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.*; 
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; 

import javax.ws.rs.Produces; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.MultivaluedMap; 
import javax.ws.rs.ext.MessageBodyWriter; 
import javax.ws.rs.ext.Provider; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.Type; 

/** 
* Created by jayen on 17/12/13. 
*/ 
@SuppressWarnings({"DefaultFileTemplate"}) 
@Produces({"application/json", "application/*+json"}) 
@Provider 
public class ResponseJSONWriter implements MessageBodyWriter<Response> { 
    @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     return Response.class.isAssignableFrom(type); 
    } 

    @Override 
    public long getSize(Response response, Class<?> type, Type genericType, Annotation[] annotations, 
         MediaType mediaType) { 
     return -1; 
    } 

    @Override 
    public void writeTo(Response response, Class<?> type, Type genericType, Annotation[] annotations, 
         MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) 
    throws IOException, WebApplicationException { 
     try { 
      ObjectMapper mapper = new ObjectMapper(); 
      mapper.registerModule(new JaxbAnnotationModule()); 
      mapper.setSerializerFactory(
        mapper.getSerializerFactory().withSerializerModifier(new BeanSerializerModifier() { 
         @Override 
         public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, 
                    JsonSerializer<?> serializer) { 
          return new FlushingSerializer<>(serializer); 
         } 
        })); 
      mapper.writeValue(entityStream, response); 
     } catch (Throwable e) { 
      e.printStackTrace(); 
     } 
    } 

    private class FlushingSerializer<T> extends JsonSerializer<T> { 
     private final JsonSerializer<T> serializer; 

     public FlushingSerializer(JsonSerializer<T> serializer) { 
      this.serializer = serializer; 
     } 

     @Override public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) 
     throws IOException, JsonProcessingException { 
      serializer.serialize(value, jgen, provider); 
      jgen.flush(); 
     } 
    } 
}