Close

Jackson - JSON to Java tree model

[Last Updated: Aug 11, 2020]

Jackson provides com.fasterxml.jackson.databind.JsonNode which can be used for JSON tree traversal. This can be thought of as being similar to DOM nodes in XML DOM trees.

To obtain JsonNode we can use following methods of ObjectMapper

package com.fasterxml.jackson.databind;
 ........
public class ObjectMapper  extends ObjectCodec  implements Versioned,  java.io.Serializable{
    ........
    public JsonNode readTree(InputStream in) throws IOException{....}
    public JsonNode readTree(Reader r) throws IOException {....}
    public JsonNode readTree(String content) throws IOException {....}
    public JsonNode readTree(byte[] content) throws IOException {....}
    public JsonNode readTree(File file)throws IOException, JsonProcessingException{....}
    public JsonNode readTree(URL source) throws IOException {....}
    ........
}

JsonNode

Following is a quick snippet of JsonNode:

package com.fasterxml.jackson.databind;
 ...
public abstract class JsonNode extends JsonSerializable.Base 
                          implements TreeNode, Iterable<JsonNode>{
    
    public abstract <T extends JsonNode> T deepCopy();

    public int size() { .... }

    // Accessing value of the specified element of an array node
    public abstract JsonNode get(int index);
    //Method for accessing value of the specified field of an object node
    public JsonNode get(String fieldName) { ..... }
    //similar to get(....), except that instead of returning null,  a "missing node"  will be returned.
    public abstract JsonNode path(String fieldName);
    
    public Iterator<String> fieldNames(){...}

    //Method for locating node specified by given JSON pointer instances
    public final JsonNode at(JsonPointer ptr){....}

    //Convenience method that is functionally equivalent to:
    //  return at(JsonPointer.valueOf(jsonPointerExpression))
    public final JsonNode at(String jsonPtrExpr) {....}

    protected abstract JsonNode _at(JsonPointer ptr);

    //Return the type of this node
    public abstract JsonNodeType getNodeType();
	
    public final boolean isValueNode() {....}
    public final boolean isContainerNode() {....}
    public boolean isMissingNode() {....}
    public boolean isArray() {.....}
    public boolean isObject() {....}
    public final boolean isPojo() {....}
    public final boolean isNumber() {...}
    public boolean isIntegralNumber() { ....}
    public boolean isFloatingPointNumber() { ..... }
    public boolean isShort() { .... }
    public boolean isInt() { .... }
    public boolean isLong() { .... }
    public boolean isFloat() { .... }
    public boolean isDouble() { .... }
    public boolean isBigDecimal() { .... }
    public boolean isBigInteger() { .... }
    public final boolean isTextual() { .... }
    public final boolean isBoolean() { .... }
    public final boolean isNull() { .... }
    public final boolean isBinary() { .... }

    //conversion
    public boolean canConvertToInt() { .... }
    public boolean canConvertToLong() { .... }
    public String textValue() { .... }
    public byte[] binaryValue() { .... }
    public boolean booleanValue() { .... }
    public Number numberValue() { .... }
    public short shortValue() { .... }
    public int intValue() { .... }
    public long longValue() { .... }
    public float floatValue() { .... }
    public double doubleValue() { .... }
    public BigDecimal decimalValue() { .... }
    public BigInteger bigIntegerValue() { .... }
    
    public abstract String asText();
    public String asText(String defaultValue) {...}
    public int asInt() {...}
    public int asInt(int defaultValue) {....}
    public long asLong() {.....}
    public long asLong(long defaultValue) {....}
    public double asDouble() {.....}
    public double asDouble(double defaultValue) {....}
    public boolean asBoolean() {.....}
    public boolean asBoolean(boolean defaultValue) {....}
    public boolean has(String fieldName) {.....}
    public boolean has(int index) {.....}
    public boolean hasNonNull(String fieldName) {....}
    public boolean hasNonNull(int index) {.....}

    public final Iterator<JsonNode> iterator() { ....}
    public Iterator<JsonNode> elements() {....}
    public Iterator<Map.Entry<String, JsonNode>> fields() {...}
	
    public abstract JsonNode findValue(String fieldName);
    public final List<JsonNode> findValues(String fieldName){....}
    public final List<String> findValuesAsText(String fieldName){...}
    
    public abstract JsonNode findPath(String fieldName);
    public abstract JsonNode findParent(String fieldName);
   
    public final List<JsonNode> findParents(String fieldName){....}

    public abstract List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar);
    public abstract List<String> findValuesAsText(String fieldName, List<String> foundSoFar);
    public abstract List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar);

    // Method for Object nodes, to access a property that has Object value; 
    //or if no such property exists, to create, add and return such Object node.
    public JsonNode with(String propertyName) {....}
    public JsonNode withArray(String propertyName) {....}
}

Example

package com.logicbig.example;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import java.io.IOException;

public class ExampleMain {
  public static void main(String[] args) throws IOException {
      String inputJson = "{\"name\":\"Jake\",\"salary\":3000,\"phones\":"
              + "[{\"phoneType\":\"cell\",\"phoneNumber\":\"111-111-111\"},"
              + "{\"phoneType\":\"work\",\"phoneNumber\":\"222-222-222\"}],"
              +"\"taskIds\":[11,22,33],"
              + "\"address\":{\"street\":\"101 Blue Dr\",\"city\":\"White Smoke\"}}";
      System.out.println("input json: " + inputJson);

      ObjectMapper objectMapper = new ObjectMapper();
      JsonNode rootNode = objectMapper.readTree(inputJson);
      System.out.printf("root: %s type=%s%n", rootNode, rootNode.getNodeType());
      traverse(rootNode, 1);
  }

  private static void traverse(JsonNode node, int level) {
      if (node.getNodeType() == JsonNodeType.ARRAY) {
          traverseArray(node, level);
      } else if (node.getNodeType() == JsonNodeType.OBJECT) {
          traverseObject(node, level);
      } else {
         throw new RuntimeException("Not yet implemented");
      }
  }

  private static void traverseObject(JsonNode node, int level) {
      node.fieldNames().forEachRemaining((String fieldName) -> {
          JsonNode childNode = node.get(fieldName);
          printNode(childNode, fieldName, level);
          //for nested object or arrays
          if (traversable(childNode)) {
              traverse(childNode, level + 1);
          }
      });
  }

  private static void traverseArray(JsonNode node, int level) {
      for (JsonNode jsonArrayNode : node) {
          printNode(jsonArrayNode, "arrayElement", level);
          if (traversable(jsonArrayNode)) {
              traverse(jsonArrayNode, level + 1);
          }
      }
  }

  private static boolean traversable(JsonNode node) {
      return node.getNodeType() == JsonNodeType.OBJECT ||
              node.getNodeType() == JsonNodeType.ARRAY;
  }

  private static void printNode(JsonNode node, String keyName, int level) {
      if (traversable(node)) {
          System.out.printf("%" + (level * 4 - 3) + "s|-- %s=%s type=%s%n",
                  "", keyName, node.toString(), node.getNodeType());

      } else {
          Object value = null;
          if (node.isTextual()) {
              value = node.textValue();
          } else if (node.isNumber()) {
              value = node.numberValue();
          }//todo add more types
          System.out.printf("%" + (level * 4 - 3) + "s|-- %s=%s type=%s%n",
                  "", keyName, value, node.getNodeType());
      }
  }
}
input json: {"name":"Jake","salary":3000,"phones":[{"phoneType":"cell","phoneNumber":"111-111-111"},{"phoneType":"work","phoneNumber":"222-222-222"}],"taskIds":[11,22,33],"address":{"street":"101 Blue Dr","city":"White Smoke"}}
root: {"name":"Jake","salary":3000,"phones":[{"phoneType":"cell","phoneNumber":"111-111-111"},{"phoneType":"work","phoneNumber":"222-222-222"}],"taskIds":[11,22,33],"address":{"street":"101 Blue Dr","city":"White Smoke"}} type=OBJECT
|-- name=Jake type=STRING
|-- salary=3000 type=NUMBER
|-- phones=[{"phoneType":"cell","phoneNumber":"111-111-111"},{"phoneType":"work","phoneNumber":"222-222-222"}] type=ARRAY
|-- arrayElement={"phoneType":"cell","phoneNumber":"111-111-111"} type=OBJECT
|-- phoneType=cell type=STRING
|-- phoneNumber=111-111-111 type=STRING
|-- arrayElement={"phoneType":"work","phoneNumber":"222-222-222"} type=OBJECT
|-- phoneType=work type=STRING
|-- phoneNumber=222-222-222 type=STRING
|-- taskIds=[11,22,33] type=ARRAY
|-- arrayElement=11 type=NUMBER
|-- arrayElement=22 type=NUMBER
|-- arrayElement=33 type=NUMBER
|-- address={"street":"101 Blue Dr","city":"White Smoke"} type=OBJECT
|-- street=101 Blue Dr type=STRING
|-- city=White Smoke type=STRING

Example Project

Dependencies and Technologies Used:

  • jackson-databind 2.9.8: General data-binding functionality for Jackson: works on core streaming API.
  • JDK 11
  • Maven 3.5.4

JSON to Java tree model Select All Download
  • jackson-tree-traversing-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ExampleMain.java

    See Also