Search code examples
javagsontreemap

Remove the key-value pairs (nested at any level) from a Json String using LinkedTreeMap


I have a Json String representing a object which further has another nested objects. Also, I have a list of keys which I need to remove from this Json String. These keys can be at any nested level of object inside this string. Finally I need to compare this edited Json string to another string and output the differences. I need to remove those key-value pairs from first Json string because I need to ignore those keys during comparison. Currently, I am converting the Json String to LinkedTreeMap provided by Gson API and then doing Map.difference() to compare. Please suggest a solution to this.


Solution

  • I did it by traversing recursively inside the Nested LinkedTreeMap till I find the field and remove it if it exists. The full path of Key needs to be provide to get the exact key-value location inside the Object (like "objects.desc" in the below Json Sample to remove desc from the Json String)

    Json Sample:

    {
        "message": "MSG",
        "code": "COD001",
        "objects": [
            {
                "resource": "Student",
                "field": "StudentId",
                "desc": "Student Description"
            }
        ]
    }
    

    Code Sample:

    public MapDifference<String, Object> getMapDifference(String jsonString1, String jsonString2) {
        MapDifference<String, Object> mapDifference = null;
        Gson gson = new Gson();
        Type mapType = new TypeToken<Map<String, Object>>() {
        }.getType();
        Map<String, Object> firstMap = gson.fromJson(jsonString1, mapType);
        Map<String, Object> secondMap = gson.fromJson(jsonString2, mapType);
        firstMap = CollectionUtils.isEmpty(firstMap) ? new HashMap<>() : firstMap;
        secondMap = CollectionUtils.isEmpty(secondMap) ? new HashMap<>() : secondMap;
        //This contains the List of keys that is required to be filtered out from Json Strings before comparision like {"message", "objects.desc"}
        List<String> firstIgnoreList = getIgnoreList1();
        List<String> secondIgnoreList = getIgnoreList2();
    
        filterKeys(firstMap, firstIgnoreList);
        filterKeys(secondMap, secondIgnoreList);
    
        mapDifference = Maps.difference(firstMap, secondMap);
        return mapDifference;
      }
    
    
    private void filterKeys(Map<String, Object> keyMap, List<String> ignoreList) {
        if (!(CollectionUtils.isEmpty(keyMap) || CollectionUtils.isEmpty(ignoreList))) {
            ignoreList.stream().parallel().forEach(key -> recursiveRemove(keyMap, key));
        }
      }
    
    private static void recursiveRemove(Map<String, Object> keyMap, String key) {
        List<String> path = Arrays.asList(StringUtils.split(key.trim(), "."));
        int size = path.size();
        int index = 0;
        List<LinkedTreeMap> treeMapList = new ArrayList<LinkedTreeMap>();
        treeMapList.add((LinkedTreeMap) keyMap);
        while (index != size - 1) {
          int i = index++;
          List<LinkedTreeMap> treeMapListTemp = new ArrayList<LinkedTreeMap>();
          treeMapList.stream().parallel().forEach(treeMap -> {
            Object obj = treeMap.get(path.get(i));
            if (obj instanceof List) {
              treeMapListTemp.addAll((List<LinkedTreeMap>) obj);
            } else if (obj instanceof LinkedTreeMap) {
              treeMapListTemp.add((LinkedTreeMap) obj);
            }
          });
          treeMapList = treeMapListTemp;
        }
        treeMapList.stream().parallel().forEach(treeMap -> treeMap.remove(path.get(size - 1)));
      }