4

I'm parsing a json using Jackson's JsonNode. My json structure looks like this (let this be variable rawJson):

{
    <some fields...>,
    "results" : [
            {
                "name" : "name1",
                "data" : ...,
                "values" : 13
            }, 
            {
                "name" : "name2",
                "data" : ...,
                "values" : 20
            },
            .
            .
            .
            {
                "name" : "name_n",
                "data" : ...,
                "values" : 151
            }
        ]
}

in Java:

ObjectMapper mapper = new ObjectMapper();
JsonNode results = mapper.readValue(rawJson, JsonNode.class).get("results");

How can I get the particular JsonNode element by filtering the attribute name? How about if I want to get JsonNode elements whose value greater than X? Can I accomplish these without looping through the results variable?

oikonomiyaki
  • 7,691
  • 15
  • 62
  • 101

1 Answers1

3

You can use forEach(Consumer c) (JDK 1.8+) function of java.lang.Iterable to perform list iteration. This method takes a Consumer instance which process all the values in the list. This approach can be extended to take a filter while iterating as shown below:

public static void main(String[] args) {

    ObjectMapper om = new ObjectMapper();
    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("test.json");
    try {
        JsonNode node = om.readValue(in, JsonNode.class).get("results");
        NodeFilteringConsumer consumer = new NodeFilteringConsumer(new NodeFilter() {

            @Override
            public boolean apply(JsonNode node) {
                //Filter for node with values greater than 20.
                return node.get("values").asDouble() > 20;
            }
        });

        node.forEach(consumer);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static interface NodeFilter{

    boolean apply(JsonNode node);
}

public static class NodeFilteringConsumer implements Consumer<JsonNode>{

    private NodeFilter f;

    public NodeFilteringConsumer(NodeFilter f) {
        this.f = f;
    }


    @Override
    public void accept(JsonNode t) {
        if (f.apply(t)){
            //Only filtered records reach here
            System.out.println("Filter applied on node:" + t);
        }
    }

}
Mohit
  • 1,740
  • 1
  • 15
  • 19
  • I'm restricted to Java 7 for the meantime. – oikonomiyaki Nov 30 '15 at 09:38
  • In such case, I think you will have to write a for each loop for iterating all JSONNode of results. You can re-use the NodeFilter interface though inside the for loop. – Mohit Nov 30 '15 at 09:43
  • this solution does not prevent Jackson from having to parse the entire payload. Perhaps this is what the OP wanted, so not saying it's a bad answer but I was actually looking for "how to skip the actual parsing of data when a certain condition does not hold" (this is particularly useful for huge JSON files) – Clint Eastwood Apr 03 '18 at 20:19