2

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 2

4

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);
           
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This looks promising! But the result is not a Stream<Person>, but each individual Person as a variable. It should be possible to transfer those to a stream?
You can transfer object into Stream using Stream.of(person);
3

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

1 Comment

This won't work if the JSON data is an empty array ([]). You can consider adding one more if-statement: if (jsonParser.nextToken() == JsonToken.END_ARRAY) { return Stream.empty(); }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.