Billybong
Billybong

Reputation: 707

Parsing a subset of JSON in Java using Jackson

Given a Json, is it possible to use Jackson to only parse out a section of the message? Say that the data I'm interested in is buried in a deep hierarchy of fields and I simply do not care about creating DTO classes for each and every class.

Given a very simplified scenario I'd like to model the Telephone class without knowing anything about the structure before it:

...{
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : {
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  },
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}....

I'm thinking something in the terms of using json-path together with deserializing just the parts I'm interested of. Some pseudo:

List<Telephone> phoneNrs = parse(".my.deep.structure.persons.phoneNumbers", List<Telephone.class>);

Upvotes: 9

Views: 9413

Answers (4)

absurdhero
absurdhero

Reputation: 356

To do this efficiently with Jackson, use the Streaming API via the JsonParser class (http://fasterxml.github.io/jackson-core/javadoc/2.5/com/fasterxml/jackson/core/JsonParser.html).

This approach will allocate no additional memory and will not incur the cost of deserializing values for all of the skipped data. Since the code will be much longer and more difficult to read than using Jackson's ObjectMapper, only do this if profiling shows unacceptable GC activity or CPU usage during parsing.

You can skip all of the nodes that you are uninterested in until you hit the "phoneNumbers" key. Then you can call the readValueAs function to deserialize the array of phone number dictionaries like so readValueAs(new TypeReference<MyPhoneNumberType[]>()).

See also:

Upvotes: 0

GuiSim
GuiSim

Reputation: 7569

ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree("... your JSON ...");

Using the JsonNode object you can then call get("my").get("deep").get("structure") to get the node you want.

Once you got your hands on that node, a simple call to mapper.treeToValue(myDeepJsonNode, Telephone[].class) will get you your array ofTelephone. You can get a list using a TypeReference as well.

To get to your deep JsonNode you can also use the findValue and findPath methods.

The Javadoc: https://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/JsonNode.html

Upvotes: 14

dimas
dimas

Reputation: 387

You can use JsonPath library. With this library you can map your JsonPath output directly into POJO's.

Pseudo:

List<Telephone> phoneNrs = JsonPath.parse(json).read("$.my.deep.structure.persons.phoneNumbers", List.class);

Upvotes: 0

Srikanta
Srikanta

Reputation: 1147

Yes, it is possible the way you have mentioned in the Pseudo code. "phoneNumbers" is a key and value returned can be passed on to Jackson deserialiying.

If the response is an array of maps then you can iterate through each one of them and use the yourResponseAsJSONObject.get('phoneNumbers') method to get the value and pass it on to Jackson

or use JsonPath as mentioned by @dimas

Upvotes: 0

Related Questions