JSON output stream in Spring MVC

My application is built using Spring boot (1.3.3.RELEASE) with Spring mvc, Spring jpa hibernate data. MySql is the database, and Jackson is the Json serializer. On java 8.

I want to return a huge dataset to my controller method. Instead of fetching all the data and then going to the jackson serializer, I want to return a stream of objects, as shown below:

@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; } 

my DAO is as follows:

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

However, Jackson serializes the stream object instead of the contents of the stream. Actual result below:

 {"parallel" : false} 

How can I train Jackson to serialize content, not a stream object?

+10
java rest jackson spring-mvc java-stream
source share
4 answers

Thanks to this I was able to solve the problem.

I have provided a custom httpMessageConverter that understands how to handle streams. For example:

 @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; } 
+13
source share

A solution is proposed https://github.com/FasterXML/jackson-modules-java8/issues/3 , which may be the best way.

I will not embed the code here, as it may be updated in this problem.

So far, I have not found any problems with this suggested code, which I have added in other modules such as Jdk8Module for optional as

 jacksonObjectMapper.registerModule(new StreamModule()); 
+1
source share

I found that this way of adding support for streams broke the nice output of LocalDate / LocalDateTime, eventually doing it like this:

 @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; } 
0
source share

Convert it like this: Iterable<X> iterable = stream::iterator; Then return Iterable, not Stream.

 @RequestMapping(value = "/candidates/all", method = RequestMethod.GET) public Iterable<Candidate> getAllCandidates(){ ... return candidateDao.findAllByCustomQueryAndStream()::iterator; 
0
source share

All Articles