Java Jackson update json 2nd value instance in array

55 Views Asked by At

Hey all I am trying to figure out how to go about updating a part of my json. So far I have not found anywhere that shows me how to do this.

For an example, this is what I am needing to update:

{
    "lastUpdated": "",
    "firetvs": [
        {
            "name": "lr",
            "ip": "",
            "mac": "",
            "token": ""
        },
        {
            "name": "mbr",
            "ip": "",
            "mac": "",
            "token": ""
        },...ETC....

So I am needing to update the data under the

"name": "mbr"
 "mac": ""

part which I would need to update the mac address to something like:

"name": "mbr"
 "mac": "C1:41:Q4:E8:S1:98:V1"

I have found code that allows me to update a standard value like my lastUpdated but not for something that's part of an array:

String jsonObject = "{" + 
    "\"lastUpdated\": \"\"," +
    "\"firetvs\": [" +
        "{" +
            "\"name\": \"lr\"," +
            "\"ip\": \"\"," +
            "\"mac\": \"\"," +
            "\"token\": \"\"" +
        "}," +
        "{" +
            "\"name\": \"mbr\"," +
            "\"ip\": \"\"," +
            "\"mac\": \"\"," +
            "\"token\": \"\"" +
        "}" +
    "]" +
"}";

ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = null;

try {
    objectNode = objectMapper.readValue(jsonObject, ObjectNode.class);
    objectNode.put("lastUpdated", "02-08-2024");
    Log.d("test", objectNode.toPrettyString());
} catch (JsonProcessingException e) {
    throw new RuntimeException(e);
}

I did find this:

objectNode.with("firetvs").put("mac", "C1:41:Q4:E8:S1:98:V1");

But that wont work since its just going to find the first instance of "mac" and update that value instead of updating the 2nd instance of it. And I also get an error of:

Property 'firetvs' has value that is not of type ObjectNode (but com.fasterxml.jackson.databind.node.ArrayNode)

So, how would I accomplish this?

2

There are 2 best solutions below

1
Raymond Choi On BEST ANSWER

You may try JSON library Josson.

https://github.com/octomix/josson

Josson josson = Josson.fromJsonString(
    "{" +
        "\"lastUpdated\": \"\"," +
        "\"firetvs\": [" +
            "{" +
                "\"name\": \"lr\"," +
                "\"ip\": \"\"," +
                "\"mac\": \"\"," +
                "\"token\": \"\"" +
            "}," +
            "{" +
                "\"name\": \"mbr\"," +
                "\"ip\": \"\"," +
                "\"mac\": \"\"," +
                "\"token\": \"\"" +
            "}" +
        "]" +
    "}");
Map<String, JsonNode> params = Map.of(
    "$date", TextNode.valueOf("02-08-2024"),
    "$key", TextNode.valueOf("mbr"),
    "$val", TextNode.valueOf("C1:41:Q4:E8:S1:98:V1")
);
JsonNode node = josson.getNode("field(lastUpdated:$date, firetvs.field(mac:if([name=$key],$val,mac)))", params);
System.out.println(node.toPrettyString());

Output

{
  "lastUpdated" : "02-08-2024",
  "firetvs" : [ {
    "name" : "lr",
    "ip" : "",
    "mac" : "",
    "token" : ""
  }, {
    "name" : "mbr",
    "ip" : "",
    "mac" : "C1:41:Q4:E8:S1:98:V1",
    "token" : ""
  } ]
}
0
dani-vta On

If you need to update the mac address of the firetvs elements only under certain conditions, for example that name is equals to mbr, I'm providing an alternative solution with streams.

Basically, the firetvs's elements are streamed via an Iterable, then filtered by keeping only the ones with mbr as their name, and finally updated with the correct mac address.

In the following sample, I've added only a couple of elements within firetvs to not clutter the code. However, here at oneCompiler I've included more elements showing the desired output.

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        String json = "{\n" +
                "    \"lastUpdated\": \"\",\n" +
                "    \"firetvs\": [\n" +
                "        {\n" +
                "            \"name\": \"lr\",\n" +
                "            \"ip\": \"\",\n" +
                "            \"mac\": \"\",\n" +
                "            \"token\": \"\"\n" +
                "        },\n" +
                "        {\n" +
                "            \"name\": \"mbr\",\n" +
                "            \"ip\": \"\",\n" +
                "            \"mac\": \"\",\n" +
                "            \"token\": \"\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";

        String mac = "C1:41:Q4:E8:S1:98:V1";

        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.readValue(json, ObjectNode.class);
        ArrayNode firetvsNode = (ArrayNode) rootNode.get("firetvs");

        //Creating an Iterable form the Iterator of the firetvs' nodes
        Iterable<JsonNode> iterable = () -> firetvsNode.iterator();

        StreamSupport.stream(iterable.spliterator(), false)     //Streaming the firetvs' nodes
                .filter(node -> node.get("name").asText().equals("mbr"))    //Keeping only the elements with mbr as their name
                .forEach(node -> ((ObjectNode) node).put("mac", mac));  //Updating the mac address of each element

        String jsonMacReplaced = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
        System.out.println(jsonMacReplaced);
    }
}