168

I need to change a JSON attribute's value in Java, I can get the value properly but I couldn't modify the JSON.

here is the code below

  JsonNode blablas = mapper.readTree(parser).get("blablas");
    for (JsonNode jsonNode : blablas) {
        String elementId = jsonNode.get("element").asText();
        String value = jsonNode.get("value").asText();
        if (StringUtils.equalsIgnoreCase(elementId, "blabla")) {
            if(value != null && value.equals("YES")){
                 // I need to change the node to NO then save it into the JSON
            }
        }
    }

What is the best way to do this?

Kara
  • 6,115
  • 16
  • 50
  • 57
mstfdz
  • 2,616
  • 3
  • 23
  • 27
  • 4
    You could convert the JsonNode to a Java Map, e.g. `resultMap = mapper.convertValue(aJsonNode, Map.class);` modify it in the Map and then change that Map back to a JsonNode. Just saying. – MikeJRamsey56 Jul 25 '18 at 18:59

7 Answers7

295

JsonNode is immutable and is intended for parse operation. However, it can be cast into ObjectNode (and ArrayNode) that allow mutations:

((ObjectNode)jsonNode).put("value", "NO");

For an array, you can use:

((ObjectNode)jsonNode).putArray("arrayName").add(object.ge‌​tValue());
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47
  • 8
    tried for a numeric type in which I need to change the value. I got this exception: `Exception in thread "main" java.lang.ClassCastException: com.fasterxml.jackson.databind.node.IntNode cannot be cast to com.fasterxml.jackson.databind.node.ObjectNode` – balboa_21 Nov 04 '17 at 14:39
  • You need to try "IntNode" – mulya Aug 09 '19 at 11:41
  • @balboa_21 changing an integer doesn't really make sense. It's a bit like me changing 4 to 9, then everyone in the world starts counting 1, 2, 3, 9, 5, 6, 7, 8. What you want to do is change the field on the object to contain a different integer, so you want to get the object higher up as an ObjectNode, and manipulate the relevant field. – MichaelRom Oct 22 '21 at 15:35
  • 1
    "ObjectNode.put()" is deprecated, can use "set" instead. – a3765910 Apr 08 '22 at 04:53
  • 1
    error: "ObjectNode cannot be resolved to a type" – john k Apr 08 '22 at 21:02
13

Adding an answer as some others have upvoted in the comments of the accepted answer they are getting this exception when attempting to cast to ObjectNode (myself included):

Exception in thread "main" java.lang.ClassCastException: 
com.fasterxml.jackson.databind.node.TextNode cannot be cast to com.fasterxml.jackson.databind.node.ObjectNode

The solution is to get the 'parent' node, and perform a put, effectively replacing the entire node, regardless of original node type.

If you need to "modify" the node using the existing value of the node:

  1. get the value/array of the JsonNode
  2. Perform your modification on that value/array
  3. Proceed to call put on the parent.

Code, where the goal is to modify subfield, which is the child node of NodeA and Node1:

JsonNode nodeParent = someNode.get("NodeA")
                .get("Node1");

// Manually modify value of 'subfield', can only be done using the parent.
((ObjectNode) nodeParent).put('subfield', "my-new-value-here");

Credits:

I got this inspiration from here, thanks to wassgreen@

matrixanomaly
  • 6,627
  • 2
  • 35
  • 58
7

I think you can just cast to ObjectNode and use put method. Like this

ObjectNode o = (ObjectNode) jsonNode; o.put("value", "NO");

Alexander
  • 160
  • 1
  • 9
Xdsasdf
  • 94
  • 5
6

The @Sharon-Ben-Asher answer is ok.

But in my case, for an array i have to use:

((ArrayNode) jsonNode).add("value");
Alejandro
  • 164
  • 2
  • 7
2

You need to get ObjectNode type object in order to set values. Take a look at this

Community
  • 1
  • 1
Eugen Halca
  • 1,775
  • 2
  • 13
  • 26
2

Just for the sake of understanding of others who may not get the whole picture clear following code works for me to find a field and then update it

ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(JsonString);    
JsonPointer valueNodePointer = JsonPointer.compile("/GrandObj/Obj/field");
JsonPointer containerPointer = valueNodePointer.head();
JsonNode parentJsonNode = rootNode.at(containerPointer);

if (!parentJsonNode.isMissingNode() && parentJsonNode.isObject()) {
    ObjectNode parentObjectNode = (ObjectNode) parentJsonNode;
    //following will give you just the field name. 
    //e.g. if pointer is /grandObject/Object/field
    //JsonPoint.last() will give you /field 
    //remember to take out the / character 
    String fieldName = valueNodePointer.last().toString();
    fieldName = fieldName.replace(Character.toString(JsonPointer.SEPARATOR), StringUtils.EMPTY);
    JsonNode fieldValueNode = parentObjectNode.get(fieldName);

    if(fieldValueNode != null) {
        parentObjectNode.put(fieldName, "NewValue");
    }
}
Mubashar
  • 12,300
  • 11
  • 66
  • 95
0
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> nodeMap = mapper.convertValue(jsonNode, new TypeReference<Map<String, Object>>(){});
nodeMap.put("key", "value");
jsonNode = mapper.convertValue(nodeMap, JsonNode.class);
Anurag Bhalekar
  • 830
  • 7
  • 9