Поток JSON-выхода в Spring MVC

Мое приложение построено с помощью Spring boot (1.3.3.RELEASE) с Spring mvc, Spring данными jpa hibernate. MySql - это база данных, а Jackson - сериализатор Json. На java 8.

Я хочу вернуть огромный набор данных в свой метод контроллера. Вместо того, чтобы извлекать все данные и затем переходить в сериализатор jackson, я хочу вернуть поток объектов, как показано ниже:

@RequestMapping(value = "/candidates/all", method = RequestMethod.GET)
public Stream<Candidate> getAllCandidates(){
    try { 
        return candidateDao.findAllByCustomQueryAndStream();
    } catch(Exception e){
        LOG.error("Exception in getCandidates",e);
    }
    return null;
}

мой DAO выглядит следующим образом:

@Query("select c from Candidate c")
public Stream<Candidate> findAllByCustomQueryAndStream();

Однако Джексон сериализует объект потока вместо содержимого потока. Фактический результат ниже:

{"parallel" : false}

Как я могу обучить Джексона сериализации содержимого, а не объекта потока?

Ответ 1

Благодаря this Я смог решить проблему.

Я предоставил пользовательский httpMessageConverter, который понимает, как обрабатывать потоки. Например:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
 MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
 ObjectMapper objectMapper =jsonConverter.getObjectMapper();
 SimpleModule module = new SimpleModule("Stream");
 module.addSerializer(Stream.class, new JsonSerializer<Stream>() {


    @Override
    public void serialize(Stream value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        serializers.findValueSerializer(Iterator.class, null)
        .serialize(value.iterator(), gen, serializers);

    }
});

 objectMapper.registerModule(module);
 jsonConverter.setObjectMapper(objectMapper);
 return jsonConverter;
}

Ответ 2

Предлагается решение https://github.com/FasterXML/jackson-modules-java8/issues/3, которое может быть лучшим способом.

Я не буду вставлять код здесь, так как он может быть обновлен в этой проблеме.

До сих пор я не обнаружил никаких проблем с этим предлагаемым кодом, который я добавил в других модулях, таких как Jdk8Module для необязательных как

jacksonObjectMapper.registerModule(new StreamModule());

Ответ 3

Я обнаружил, что этот способ добавления поддержки для потоков нарушил приятный вывод LocalDate/LocalDateTime, в итоге сделал это следующим образом:

@Bean
public Module customModule() {
    SimpleModule module = new SimpleModule("Stream");
    module.addSerializer(Stream.class, new JsonSerializer<Stream>() {

        @Override
        public void serialize(Stream value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException, JsonProcessingException {
            serializers.findValueSerializer(Iterator.class, null)
                    .serialize(value.iterator(), gen, serializers);

        }
    });
    return module;
}

Ответ 4

Преобразуйте это так: Iterable<X> iterable = stream::iterator; , Тогда верните Iterablе, а не Stream.

@RequestMapping(value = "/candidates/all", method = RequestMethod.GET)
public Iterable<Candidate> getAllCandidates(){
    ...

        return candidateDao.findAllByCustomQueryAndStream()::iterator;