1

So, I've looked around for this answer but I haven't found a solution that mirrors my situation. Basically, I have a JSON structure that looks like:

{
    "count": 4424,
    "results": [
        {"id": 2718, "name": "fox", "location": "Omaha"}, 
        {"id": 2719, "name": "bear", "location": "Miami"}
        ...
        more objects containing an ID field
        ...
    ]
}

I want to be able to parse out all of the "id" values and store them in a list which I will loop over to make subsequent REST calls to other end points. If I wanted the entire object containing the id field, I know I could create a new object and create a custom JSON deserializer, but since it is just one field I want, that feels like overkill.

My initial thought was to do something in a custom deserializer, like so:

List<String> idList = new ArrayList<String>();
JsonNode node = jp.getCodec().readTree(jp); // jp = JsonParser
JsonNode resultsNode = node.get("results");
resultsNode.forEach(result -> {
    JsonNode idNode = result.get("id");
    if (idNode != null) {
        String id = idNode.textValue().toUpperCase();
        idList.add(id);
    }
});

Would that be the correct way to handle this? If not, what would be the best/efficient way to parse these id values into a list?

Also, I was reading online about maybe wanting to do caching when attempting something like this (list may contain 1000+ IDs), but I'm not quite sure what that means in this scenario. Would anyone be able to explain that?

2 Answers 2

1

Without having tried it, this looks like a JSON-file that would come from serializing a Sightings-object from something like

public AnimalSighting {
    public int id;
    public String name;
    public String location;
}
public Sightings {
    public int count;
    public ArrayList<AnimalSighting> results;
}

Then deserialization would be straightforward with new ObjectMapper().readValue(file, Sightings.class);

Of course the classes could use private attributes with getters and setters and then possibly need some annotations (@JsonCreator/@JsonProperty/@JsonGetter/@JsonSetter, depending on what exactly you are doing), but the general principle remains.

Sign up to request clarification or add additional context in comments.

8 Comments

So my initial thought was to do something like this, but wouldn't it be overkill in terms of having to create a new object for each item in the JSON array, especially if I'm not going to make use of any of the other attributes besides id? Wouldn't it be better performance wise to parse the string value and store it in a list?
In the end you will have one Sightings-object with a list of AnimalSighting-objects. I fail to see how this would be any more "complicated" than having a list of Strings. Or maybe I'm misunderstanding what String value you are talking about? Can the id be a String instead of just integers as shown in the example?
@Pr0pagate A String isn't an Object?
If the concern is memory management, offloading the data into a database until needed seems like a better solution than keeping a converted string representation of the data in memory.
I just tested my suggestion: it takes roughly 10 seconds to deserialize a sample JSON-file with 10 million entries (so that file has a size of around 1GB). So if you have "only" 1000+ entries, performance should not be too much of a concern.
|
1

If you need only a part of JSON payload you can use JsonPath library. Below you can find an example how to use it:

import com.jayway.jsonpath.JsonPath;

import java.io.File;
import java.util.List;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        List<String> ids = JsonPath.read(jsonFile, "$.results.[*].id");
        System.out.println(ids);
    }
}

Above code prints:

[2718,2719]

With Jackson you can create as small POJO model as needed:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        List<Id> ids = mapper.readValue(jsonFile, Response.class).getIds();
        System.out.println(ids);
    }
}

class Response {

    private final List<Id> ids;

    @JsonCreator
    public Response(@JsonProperty("results") List<Id> ids) {
        this.ids = ids;
    }

    public List<Id> getIds() {
        return ids;
    }
}

class Id {

    private final String id;

    @JsonCreator
    public Id(@JsonProperty("id") String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Override
    public String toString() {
        return id;
    }
}

Above code prints:

[2718, 2719]

FAIL_ON_UNKNOWN_PROPERTIES feature is required if we do not want to map all properties. It should not be much slower than your solution with custom deserialiser.

1000+ JSON objects on list is not a huge number and should not be a problem. You can try to write benchmarks for each solution and compare results.

Comments

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.