gnjago
gnjago

Reputation: 3511

Read part of a JSON String using Jackson

The JSON string is as follows

{
   "rank":"-text_relevance",
   "match-expr":"(label 'star wars')",
   "hits":{
      "found":7,
      "start":0,
      "hit":[
         {"id":"tt1185834",
             "data":{
                "actor":["Abercrombie, Ian","Baker, Dee","Burton, Corey"],
                "title":["Star Wars: The Clone Wars"]
             }
         },
         .
         .
         .
         {"id":"tt0121766",
             "data":{
                "actor":["Bai, Ling","Bryant, Gene","Castle-Hughes, Keisha"],
                "title":["Star Wars: Episode III - Revenge of the Sith"]
             }
         }
       ]
    },
    "info":{
       "rid":"b7c167f6c2da6d93531b9a7b314ad030b3a74803b4b7797edb905ba5a6a08",
       "time-ms":2,
       "cpu-time-ms":0
    }
    } 

It has many fields, but I just have want the Data field. This won't work:

mapper.readvalue(jsonString,Data.class); 

How do I make Jackson read just the "Data" field?

Upvotes: 27

Views: 32975

Answers (3)

catorda
catorda

Reputation: 479

Jackson 2.3 now has a JsonPointer class you can use. There's a simple example in their quick overview for the release.

Usage is simple: for JSON like

{
    "address" : { "street" : "2940 5th Ave", "zip" : 980021 },   
    "dimensions" : [ 10.0, 20.0, 15.0 ] 
}

you could use expressions like:

  JsonNode root = mapper.readTree(src); 
  int zip =root.at("/address/zip").asIntValue(); 
  double height = root.add("/dimensions/1").asDoubleValue();// assuming it's the second number in there

Upvotes: 34

pb2q
pb2q

Reputation: 59607

I think that the easiest way to do this is using the Jackson TreeModel: let Jackson parse the JSON input into a JsonNode object that you then query, assuming some knowledge of the data structure. This way you can ignore most of the data, walking down the JsonNodes to the data that you want.

// String input = The JSON data from your question
ObjectMapper mapper = new ObjectMapper();

JsonNode rootNode = mapper.readValue(input.getBytes(), JsonNode.class); 

// can also use ArrayNode here, but JsonNode allows us to get(index) line an array:
JsonNode hits = rootNode.get("hits");

// can also use ObjectNodes here:
JsonNode oneHit = null;
JsonNode dataObj = null;

int idx = 0;

Data data = null;


if (hits != null)
{
    hits = hits.get("hit");

    if (hits != null)
    {
        while ((oneHit = hits.get(idx)) != null)
        {
            dataObj = oneHit.get("data");
            System.out.println("Data[" + idx + "]: " + dataObj);
            idx++;
        }
    }
}

Output:

 Data[0]: {"id":"tt1185834","data":{"actor":["Abercrombie, Ian","Baker, Dee","Burton, Corey"],"title":["Star Wars: The Clone Wars"]}}
 Data[1]: {"id":"tt0121766","data":{"actor":["Bai, Ling","Bryant, Gene","Castle-Hughes, Keisha"],"title":["Star Wars: Episode III - Revenge of the Sith"]}}

You can still use your Data class implementation, but I believe this will require getting the String representing each data - as above relying on toString, or using JsonNode.getText() - and re-parsing it using the ObjectMapper:

mapper.readValue(dataArray, Data.class));

The alternative is to use the Jackson Streaming Model, and intercept the nodes yourself until you see the part of the input that marks the beginning of each data element, then consume the string and call objectMapper.readValue on the contents, for each string.

Upvotes: 15

Biju Kunjummen
Biju Kunjummen

Reputation: 49915

Json-path could be a very good alternative for such a requirement - if you are okay with a solution other than Jackson that is: http://code.google.com/p/json-path/

Upvotes: 5

Related Questions