Небуферизованный CXF (без заголовка длины содержимого)

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

Как я могу передавать JAXB-бины с CXF?

1 ответ

Мне удалось сделать это с Джексоном и моим собственным 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();
        }
    }
}
Другие вопросы по тегам