Processing model: Tree Model

Of 3 major processing modes that Jackson supports, Tree Model may be most familiar to developers with experience using XML as the main data/transfer format. At conceptual level it has many similarities to DOM XML tree model; although there are also many differences due to structural and semantic differences between JSON and XML.

Constructing Trees from JSON content

Trees are usually constructed using ObjectMapper, similar to how Data Binding is done. There are actually two distinct methods for doing this:

   1   // general method, same as with data binding
   2   ObjectMapper mapper = new ObjectMapper();
   3   // (note: can also use more specific type, like ArrayNode or ObjectNode!)
   4   JsonNode rootNode = mapper.readValue(src, JsonNode.class); // src can be a File, URL, InputStream etc
   5 
   6   // or, with dedicated method; requires a JsonParser instance
   7   JsonParser jp = ...; // construct using JsonFactory (can get one using ObjectMapper.getJsonFactory)
   8   rootNode = mapper.readTree(jp);
   9   // (most useful when binding sub-trees)

Traversing Tree Model

Basic JsonNode interface has most accessor methods (although none of methods to change tree). For basic traversal, there are separate methods for JSON Objects and Arrays -- Objects are indexed by property name, Arrays by element index. In addition, it is possible to use "safe" methods which will return dummy MissingNode instead of null if Object/Array does not contain indicated value. Methods available thus are:

So considering following JSON document:

  {
    "array" : [ 1, { "name" : "Billy" }, null ],
    "object" : { "id" : 123, "names" : [ "Bob", "Bobby" ]  }
  }

as 'root' we could access information using methods like:

  JsonNode array = root.get("array"); // would return null if none found
  // let's use "path()" -- if no such element, will return MissingNode which can be dereferenced!
  String name = array.path(1).getValueAsText(); // or, getTextValue if it's certain it is JSON String
  String id = root.path("object").path("id").getTextValue(); // so it'll be null if not found
  // or
  JsonNode idNode = root.path("object").path("id"); // never returns null
  if (idNode.isMissingNode()) {
    throw new IllegalArgumentException("Could not find id!");
  }

  // or maybe we just want to traverse all values of properties of the array node?
  for (JsonNode node : root.path("array")) {
    System.out.println("Entry: "+node.toString());
  }

Even better, we could also do:

  root.with("object").with("attrs").put("firstAttribute", 1);

and tree being modified to look like:

  {
    "array" : [ 1, { "name" : "Billy" }, null ],
    "object" : {
      "id" : 123,
      "names" : [ "Bob", "Bobby" ],
      "attrs" : { "firstAttribute" : 1 }
    }
  }

which is much more convenient than having to check for existence (or lack thereof) along the path.

Note that the main difference between path() and with() therefore is that former works well with read-access, and latter works better when modifying things.

TO BE COMPLETED

(what else should be added here?)

Constructing Tree Model instances from Scratch

It is also possible to construct tree instances without external JSON source.

For example:

   1   ObjectMapper mapper = new ObjectMapper();
   2   JsonNode rootNode = mapper.createObjectNode(); // will be of type ObjectNode
   3   ((ObjectNode) rootNode).put("name", "Tatu");
   4   // ... and so forth

Writing Trees as JSON

Writing out Trees is done exactly the same way as writing out regular Java objects as JSON; that is:

  mapper.writeValue(dst, myBean); // dst can be File, OutputStream, Writer etc

Converting to Token Stream

(note: available since version 1.3)

Assuming you have a JsonNode, you can also create a JsonParser to traverse its contents as if it was a token stream] by:

  JsonParser jp = node.traverse();
  // or:
  JsonParser jp = mapper.treeAsTokens(node);

Converting to Java Objects

(note: available since version 1.3)

You can do conversion explicitly by first converting Tree to Token Stream (as above) and then binding; but there is a short-cut too:

   MyBean bean = mapper.treeToValue(node, MyBean.class);

Additional Reading


CategoryJackson

JacksonTreeModel (last edited 2011-12-02 04:19:00 by TatuSaloranta)

Copyright ©2009 FasterXML, LLC