Using the Jackson streaming api for JSON, how do I while loop through an object?

家住魔仙堡 提交于 2019-12-12 02:26:29

问题


    ObjectMapper map = new ObjectMapper(); //for later inner object data binding
    JsonParser p = map.getFactory().createParser(new File("test.json"));
    //start the tokenizing of object
    p.nextToken();
    //loop until the end object is found, simultaneously incrementing loop
    while (p.nextToken() != JsonToken.END_OBJECT) {
        //...
    }
    p.close(); 

(note, there is probably a better way to do what I am trying to do here and I welcome any advice on how to do this better, but please also tell me if my current technique is possible)

This is the code I currently have and have not gone any further because I realized a flaw. This code was taken from a Jackson streaming API tutorial and I am trying to adapt it to my project.

What I am trying to do is loop through the tokens of an object in a json file from the start of the object to its end. However, this json file contains many inner objects, and the loop may end prematurely at the END_OBJECT of an inner object.

What I thought then was, maybe I could try to make the while loop end more specifically: only when it encounters the corresponding END_OBJECT of its START_OBJECT. I have looked in the Jackson docs (at JsonParser and JsonToken) but I cannot figure out how I would do this programmatically.

My question then is, how do I write a while loop that loops through one object only? How do I uniquely define the end of the object? I thought about storing the initial start object JsonToken in memory but I am not sure how I could compare it to the end object token to see if the two are related at all. The Jackson docs aren't too descriptive on this or maybe I am too wishful and naive.

I am using a mapper because I will be doing a mix of data binding and streaming in this method. I only need to data bind the inner objects.

The first object contains an array, "decks"

The inner object contains a deck's cards (also an array).

I will be data binding single cards (as I have looked extensively but have not found an easier way to data bind inner objects (cards) while retaining some information of the "deck" they came from).


回答1:


Specifically regarding the way you do it, the simplest general solution would be counting the START_OBJECT encountered vs the END_OBJECT (same exercise in CS classes of knowing if an expression contains the correct number of opening and closing parenthesis). So your code would look like:

ObjectMapper map = new ObjectMapper(); //for later inner object data binding
JsonParser p = map.getFactory().createParser(new File("test.json"));
//start the tokenizing of object
p.nextToken();
// Assuming the first token you encounter is the START_OBJECT, otherwise start from 0.
int startEndCounter = 1;
//loop until the end object is found, simultaneously incrementing loop
while (startEndCounter != 0) {
    //...
    if (p.nextToken() == JsonToken.STAR_OBJECT) {
        startEndCounter++;    
    } else if (p.nextToken() == JsonToken.END_OBJECT) {
        startEndCounter--;    
    }
}
p.close();

And the Jackson way to read an object using the parser:

Card card = mapper.readValue(jp, Card.class);

Here's a variation of an example from the fasterxml wiki, which will read a Card object on each iteration:

JsonParser jp = map.getFactory().createParser(new File("test.json"));
// advance stream to START_ARRAY first:
jp.nextToken();
// and then each time, advance to opening START_OBJECT
while (jp.nextToken() == JsonToken.START_OBJECT)) {
Card card = mapper.readValue(jp, Card.class);
   // process
   // after binding, stream points to closing END_OBJECT
}



回答2:


If you reach the end of the stream, call to parser.nextToken() will return null. You can iterate until null is returned like so and build your desired object:

            Object myObject; 
            List<Object> myObjects = new ArrayList()
            JsonToken nextToken = parser.nextToken()
            while (nextToken != null) {
                nextToken = parser.nextToken()
                if (nextToken == JsonToken.START_OBJECT) {myObject = new Object()}
                else if (nextToken == JsonToken.END_OBJECT){myObjects.add(myObject)}
                else {
                       if(parser.currentName == "myProperty"){
                           parser.nextToken()
                           myObject.property = parser.getValue()
                        }
                     }


来源:https://stackoverflow.com/questions/25425939/using-the-jackson-streaming-api-for-json-how-do-i-while-loop-through-an-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!