Поток 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;