How to parse an input stream of JSON into a new stream with Jackson

Viewed 825

I have an InputStream containing an array of JSON objects. Each individual object can be parsed to a Java class Person using Jackson's ObjectMapper:

public class Person {
    public String name;
    public Int age;
    ...
}

InputStream myStream = connection.getInputStream(); // [{name: "xx", age: 00}, {...}]

ObjectMapper objectMapper = new ObjectMapper();

How do I parse the JSON-stream into a new Stream<Person> using Jackson without having all the data in the memory?

2 Answers

You can do something like

private void parseJson(InputStream is) throws IOException {

    // Create and configure an ObjectMapper instance
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

    // Create a JsonParser instance
    try (JsonParser jsonParser = mapper.getFactory().createParser(is)) {

        // Check the first token
        if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
            throw new IllegalStateException("Expected content to be an array");
        }

        // Iterate over the tokens until the end of the array
        while (jsonParser.nextToken() != JsonToken.END_ARRAY) {

            // Read a contact instance using ObjectMapper and do something with it
            Person person= mapper.readValue(jsonParser, Person.class);
           
        }
    }
}

The answer by SJN is on the right track, but it still does not convert the InputStream to a Stream. JsonParser actually has a readValuesAs method that returns an iterator. Converting this iterator into a Stream is then straightforward.

Stream<Person> toStream(InputStream inputStream) throws IOException {
  ObjectMapper objectMapper = new ObjectMapper();
  JsonParser jsonParser = objectMapper.getFactory().createParser(inputStream);

  if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
    throw new IllegalStateException("Not an array");
  }
  jsonParser.nextToken(); // advance jsonParser to start of first object
  Iterator<Person> iterator = jsonParser.readValuesAs(Person.class);

  return StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
    false);
}
Related