Skip to content

Parse array JSON Schema with Jackson

I have a JSON Schema defined :

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "array",
  "title": "The Root Schema",
  "items": {
    "$id": "#/items",
    "type": "object",
    "title": "The Items Schema",
    "required": [
      "test",
      "isExpand",
      "numberOfIssue",
      "issue",
      "listOfDetails"
    ],
    "properties": {
      "test": {
        "$id": "#/items/properties/test",
        "type": "string",
        "title": "The Test Schema",
        "default": "",
        "examples": [
          "value"
        ],
        "pattern": "^(.*)$"
      },
      "isExpand": {
        "$id": "#/items/properties/isExpand",
        "type": "boolean",
        "title": "The Isexpand Schema",
        "default": false,
        "examples": [
          true
        ]
      },
      "numberOfIssue": {
        "$id": "#/items/properties/numberOfIssue",
        "type": "integer",
        "title": "The Numberofissue Schema",
        "default": 0,
        "examples": [
          1
        ]
      },
      "issue": {
        "$id": "#/items/properties/issue",
        "type": "object",
        "title": "The Issue Schema",
        "required": [
          "mappingId"
        ],
        "properties": {
          "mappingId": {
            "$id": "#/items/properties/issue/properties/mappingId",
            "type": "string",
            "title": "The Mappingid Schema",
            "default": "",
            "examples": [
              "1561561"
            ],
            "pattern": "^(.*)$"
          }
        }
      },
      "listOfDetails": {
        "$id": "#/items/properties/listOfDetails",
        "type": "array",
        "title": "The listOfDetails Schema",
        "items": {
          "$id": "#/items/properties/listOfDetails/items",
          "type": "object",
          "title": "The Items Schema",
          "required": [
            "self",
            "detailId"
          ],
          "properties": {
            "self": {
              "$id": "#/items/properties/listOfDetails/items/properties/self",
              "type": "string",
              "title": "The Self Schema",
              "default": "",
              "examples": [
                "self1"
              ],
              "pattern": "^(.*)$"
            },
            "issueId": {
              "$id": "#/items/properties/listOfDetails/items/properties/detailId",
              "type": "string",
              "title": "The detailId Schema",
              "default": "",
              "examples": [
                "000188181"
              ],
              "pattern": "^(.*)$"
            }
          }
        }
      }
    }
  }
}

It’ll always be a schema which contains firstly items and then it’ll contain properties. In properties can be more arrays or objects found so I want to do that recursively. What i’m trying to achieve is a Map<String, Object> which directly represents the schema. Where I’m getting stuck is the recursive call where current property is a object or array.

I want to achieve this:

{
  "test" : "",
   "isExpand" : false,
   "numberOfIssues" : 0,
   "issue" : {
      "mappingId" : ""
    },
   "listOfDetails" : [
     {
      "self" : "",
      "detailId" : ""
     }
    ]
}

Here is my method for parsing out the JsonSchema from file and getting the actual properties from it

    private static void parseJsonNode(String path) throws Exception {
        ObjectMapper mapper = new ObjectMapper(new JsonFactory());
        JsonNode rootNode = mapper.readTree(new File(METADATA_SCHEMA_PATH + path));
        Map<String, Object> elementsMap = new HashMap<>();
        fillHashMap(elementsMap, rootNode.get("items").get("properties"));
    }

The elementsMap is a Map<String, Object> defined globally

Map<String, Object> elementsMap = new HashMap<>();
private static Map<String, Object> fillHashMap(Map<String, Object> elementsMap, JsonNode rootNode) throws Exception {
        Iterator<Map.Entry<String, JsonNode>> fieldsIterator = rootNode.fields();
        while (fieldsIterator.hasNext()) {
            Map.Entry<String, JsonNode> field = fieldsIterator.next();
            if (field.getValue().get("type").toString().contains("array")) {
                //TODO HOW TO HANDLE ARRAY THERE
            } else if (field.getValue().get("type").toString().contains("object")) {
                elementsMap.put(field.getKey(), fillHashMap(elementsMap, field.getValue().get("properties")));
            } else {
                elementsMap.put(field.getKey(), field.getValue().get("default"));
            }
        }
        return elementsMap;
}

I’m getting stuck on the recursive call fillHashMap(). When i unbox the object properties it goes to else branch where it puts the mappingId directly to the Map, which is logical after unboxing.. but i’m guessing that i’m doing it all wrong.. Can someone point me on the things which I should change in order to achieve my desired result? Thanks !!

Answer

I figured it out myself. Maybe it’ll once help someone.

private static void parseJsonNode(String path) throws Exception {
    ObjectMapper mapper = new ObjectMapper(new JsonFactory());
    JsonNode rootNode = mapper.readTree(new File(BASE_PATH + path));
    Map<String, Object> elementsMap =
        fillHashMap(rootNode.get("items").get("properties"));
    System.out.println(elementsMap);
}
private static Map<String, Object> fillHashMap(JsonNode rootNode) {
    Map<String, Object> elementsMap = new HashMap<>();
    Iterator<Map.Entry<String, JsonNode>> fieldsIterator = rootNode.fields();
    while (fieldsIterator.hasNext()) {
        Map.Entry<String, JsonNode> field = fieldsIterator.next();
        if (field.getValue().get("type").toString().contains("array")) {
            List<Map<String, Object>> objectArray = new ArrayList<>();
            JsonNode itemsNode = field.getValue().get("items").get("properties");
            objectArray.add(fillHashMap(itemsNode));
            elementsMap.put(field.getKey(), objectArray);
        } else if (field.getValue().get("type").toString().contains("object")) {
            elementsMap.put(field.getKey(),
                 fillHashMap(field.getValue().get("properties")));
        } else {
            elementsMap.put(field.getKey(), field.getValue().get("default"));
        }
    }
    return elementsMap;
}