How to update a certain value inside this jackson JsonNode?

Viewed 710

TLDR: I want to update certain value of a JsonNode key dependsOn and return the result as a JsonNode. Currently I'm converting the value to a String, slicing the characters and then using ObjectMapper to convert the string back to JsonNode

I have a json object like shown below

{
    "name": "somename",
    "type": "sometype",
    "description": "some desc",
    "properties": {
        "path": "some path",
        
        "dependsOn": [
            "ABC:zzz","DEF:sdc","GHI:ere"
        ],
        
        "checkpoint": "some checkpoint",
        "format": "some format",
        "output": "some output",
        "table": "some table"
    }
}

I'm currently parsing the above json data and fetching the dependsOn as JsonNode element (as shown below)

JsonNode components = model.get("properties");
JsonNode dependsOn = components.get("dependsOn");

When I print dependsOn it looks like this "["ABC:zzz","DEF:sdc","GHI:ere"]"

My requirement was to strip everything after : from the dependsOn array

This below code helped me to convert the JsonNode to String and then strip :whatever then convert it back to JsonNode

if (dependsOn != null && !dependsOn.isEmpty()) {
  String dependsOnString =
          components
                  .get("dependsOn")
                  .get(0)
                  .textValue()
                  .substring(
                          0,
                          (components.get("dependsOn").get(0).textValue().lastIndexOf(":") != -1)
                                  ? components.get("dependsOn").get(0).textValue().lastIndexOf(":")
                                  : components.get("dependsOn").get(0).textValue().length());
  ObjectMapper mapper = new ObjectMapper();
  dependsOn = mapper.readTree("[\"" + dependsOnString + "\"]");
}

Input:

"["ABC:zzz","DEF:sdc","GHI:ere"]"

Output

"["ABC","DEF:sdc","GHI:ere"]"

Above code only strip the first element of the array I can loop and perform the same for rest of the elements though. But I have a couple of questions regarding whatever I'm trying to do

Firstly, am I doing this in a right way or is there a simpler technique to do this? instead of converting it to string and then again to JsonNode..

Next, I've only done this to the first element of the array and I want to loop through and do this for all the elements of the array. Is there a simpler solution to this instead of using a for/while loop?

3 Answers

You can iterate the dependsOn after casting it to ArrayNode and set value to it:

ArrayNode array = ((ArrayNode) dependsOn);
List<String> newValues = new ArrayList<>();

for(int i=0;i<array.size();i++) {
    newValues.add(array.get(i).asText().split(":")[0]);
}

array.removeAll();
newValues.forEach(array::add); 

EDIT: If you don't want your original dependsOn to be updated then use:

JsonNode copy = dependsOn.deepCopy();
// or you could invoke `deepCopy` on the `ArrayNode` as well

Now pass this copy object for slicing operation. So that the original json remains unchanged.

This should work, without convert to string and parse again to jsonNode

JsonNode prop = node.get("properties");
JsonNode arrayCopy = prop.get("dependsOn").deepCopy();
var array = ((ObjectNode)prop).putArray("dependsOn");
IntStream.range(0, arrayCopy.size())
    .forEach(index -> {
      String elem = arrayCopy.get(index).asText();
      String finalElem = elem.substring(0,elem.contains(":") ? elem.lastIndexOf(':') : elem.length());
      array.add(finalElem);
    });

Since my usecase suggests my dependsOn value should not be overridden at node level, I had to convert the JsonNode to String and then used the regular expression matcher to replace :xyz with an empty string in each element then convert it back to JsonNode

String pattern = ":[a-zA-Z]+";
        String newDependsOn = dependsOn.toString().replaceAll(pattern, "");
        ObjectMapper mapper = new ObjectMapper();
        dependsOn = mapper.readTree(newDependsOn);

@Gautham's solution did work too but what I think is it was overriding at the root and the old value wasn't available anymore outside the loop

Related