I am trying to find the type
of any element within the JSON Schema using the most memory efficient and high-performance approach. However, after reaching a certain point I am a bit stuck and running out of ideas so hoping to get an answer here:
Basically, I have a List: jsonPath
which will consist of the element along with its parent whose type I need to identify from the Json Schema
that I have. For parsing the Json Schema
I am using the Java Jackson Library
. I am able to get all the elements and able to find its type but during the comparison, I am a bit confused.
Following is the code I have so far:
As we can see I have the jsonPath
as "food", "Ingredients", "ingredient"
which means that I need to find the type
of last element ingredient
and others are its parents. The program should return type
as array
. Similarly, if I pass any other elements in the jsonPath array
such as just food
or price
then it should check for corresponding parents and their children then finally should return its type. I have used the Stack elements
just for reference purposes you can ignore that.
I can try to add multiple if
conditions at every stage and get the element type. However, I am trying to find a simple and better way rather than using complex nested if's. It should be possible to do in a much simple way but nothing is clicking at the moment for me.
public class JsonElementLocator {
private final JsonNode outerNode;
private static JsonElementLocator _instance;
// Default constructor to get the content and store in the root
private JsonElementLocator() throws IOException {
final ObjectMapper mapper = new ObjectMapper();
final JsonNode root = mapper.readTree(JsonElementLocator.class.getClassLoader().getResource("testJSON.json"));
outerNode = root.path("definitions");
}
// Method to create a Object instance of current class
private static synchronized JsonElementLocator getInstance() throws IOException {
if (_instance == null) {
_instance = new JsonElementLocator();
}
return _instance;
}
// Method called by other application to get the element Type
public static Optional < String > locate(List < String > elementPath) throws IOException {
JsonElementLocator cl = getInstance();
JsonNode rootNode = cl.outerNode;
recurse(rootNode, new Stack < String > ());
return Optional.empty();
}
// Method called recursively to get the element Type from JSON Schema
private static Optional < String > recurse(JsonNode rootNode, Stack < String > elements) {
// Loop through each Object in Root Node
for (JsonNode childNode: rootNode) {
// Check if childNode is of Object type
if (childNode.path("type").toString().contains("object")) {
elements.push(childNode.get("title").toString());
// Call recurse method for the subsequent objects
recurse(childNode.path("properties"), elements);
elements.pop();
} else if (childNode.path("type").toString().contains("array")) {
// Check if childNode is of Array type and call its elements
for (JsonNode ccNode: childNode.path("items")) {
final String def = ccNode.toString().contains("definitions") ? ccNode.toString().replace("\"", "").replaceAll("#/definitions/",
"") : null;
// Find the element from the root
if (def != null) {
final JsonNode defInfo = _instance.outerNode.get(def);
// Call recurse method for definition elements
recurse(defInfo.path("properties"), elements);
}
}
} else {
System.out.println(String.join("/", elements));
// Check if childNode is of normal type
}
}
return Optional.empty();
}
public static void main(String[] args) throws IOException {
List < String > jsonPath = new ArrayList < String > (List.of("food", "Ingredients", "ingredient"));
locate(jsonPath);
}
}
Following is the complete Json Schema
that I am trying to parse:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$ref": "#/definitions/Welcome2",
"definitions": {
"Welcome2": {
"type": "object",
"additionalProperties": false,
"properties": {
"hotelName": {
"type": "string"
},
"food": {
"type": "array",
"items": {
"$ref": "#/definitions/Food"
}
}
},
"required": [
"food",
"hotelName"
],
"title": "Welcome2"
},
"Food": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"price": {
"type": "string"
},
"description": {
"type": "string"
},
"calories": {
"type": "string",
"format": "integer"
},
"ingredients": {
"$ref": "#/definitions/Ingredients"
}
},
"required": [
"calories",
"description",
"ingredients",
"name",
"price"
],
"title": "Food"
},
"Ingredients": {
"type": "object",
"additionalProperties": false,
"properties": {
"ingredient": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"ingredient"
],
"title": "Ingredients"
}
}
}