Skip to content

Instantly share code, notes, and snippets.

@masa2146
Created July 30, 2022 11:26
Show Gist options
  • Save masa2146/ec57f1584e8d496dec9ea04eae9b9c97 to your computer and use it in GitHub Desktop.
Save masa2146/ec57f1584e8d496dec9ea04eae9b9c97 to your computer and use it in GitHub Desktop.
Extract all paths of the complex object
JsonPathExtractor.java extract all deep paths and its value as map
JsonParser.java extract only all deep paths as list
@SuppressWarnings({"unchecked", "unused"})
public class JsonParser {
private List<String> pathList;
public JsonParser(String json) throws JSONException {
this.pathList = new ArrayList<>();
setJsonPaths(json);
}
public List<String> getPathList() {
return this.pathList;
}
private void setJsonPaths(String json) throws JSONException {
this.pathList = new ArrayList<>();
JSONObject object = new JSONObject(json);
String jsonPath = "";
if (json != JSONObject.NULL) {
readObject(object, jsonPath);
}
}
private void readObject(JSONObject object, String jsonPath) throws JSONException {
Iterator<String> keysItr = object.keys();
String parentPath = jsonPath;
while (keysItr.hasNext()) {
String key = keysItr.next();
Object value = object.get(key);
if (!StringUtils.isEmpty(parentPath)) {
jsonPath = parentPath + "." + key;
} else {
jsonPath = key;
}
if (value instanceof JSONArray jsonArray) {
readArray(jsonArray, jsonPath);
} else if (value instanceof JSONObject jsonObject) {
readObject(jsonObject, jsonPath);
} else { // is a value
this.pathList.add(jsonPath);
}
}
}
private void readArray(JSONArray array, String jsonPath) throws JSONException {
String parentPath = jsonPath;
for (int i = 0; i < array.length(); i++) {
Object value = array.get(i);
jsonPath = parentPath + "[" + i + "]";
if (value instanceof JSONArray jsonArray) {
readArray(jsonArray, jsonPath);
} else if (value instanceof JSONObject jsonObject) {
readObject(jsonObject, jsonPath);
} else { // is a value
this.pathList.add(jsonPath);
}
}
}
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonPathExtractor {
private static final String DELIMITER = ".";
/**
* It takes a JsonNode and a path and returns a map of paths and values
*
* @param jsonNode The JsonNode object that we want to extract the paths and values from.
* @return A map of paths and values.
*/
public static Map<String, String> getPathsAndValues(JsonNode jsonNode) {
Map<String, String> pathMapValue = new HashedMap<>();
String path = "";
extractFieldAndValues(jsonNode, path, pathMapValue);
return pathMapValue;
}
/**
* It takes a JSON node, a path, and a map of paths to values. It iterates over the fields of the node, and for each
* field, it either adds the field to the map if it's a leaf node, or recursively calls itself if it's an object or
* array
*
* @param jsonNode The JsonNode object that is being traversed.
* @param path The path of the field in the JSON document.
* @param pathMapValue This is the map that will be returned by the method.
*/
private static void extractFieldAndValues(JsonNode jsonNode, String path, Map<String, String> pathMapValue) {
Iterator<Map.Entry<String, JsonNode>> nodeFields = jsonNode.fields();
while (nodeFields.hasNext()) {
Map.Entry<String, JsonNode> next = nodeFields.next();
String field;
field = StringUtils.isEmpty(path) ? next.getKey() : path + DELIMITER + next.getKey();
if (next.getValue().isArray()) {
ArrayNode arrayNode = (ArrayNode) next.getValue();
IntStream.range(0, arrayNode.size()).forEach(index -> {
String arrayIndexString = "[" + index + "]";
String arrayField = field + arrayIndexString;
extractFieldAndValues(arrayNode.get(index), arrayField, pathMapValue);
});
} else if (next.getValue().isObject()) {
extractFieldAndValues(next.getValue(), field, pathMapValue);
} else {
pathMapValue.put(field, next.getValue().asText());
}
}
if (!jsonNode.isObject() && !jsonNode.isArray() && jsonNode.isEmpty()) {
pathMapValue.put(path, jsonNode.asText());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment