How to modify values of JsonObject

I want to add a new field to jsonObject and this new field’s name will be based on a value of another field. To be clear, this an examples of what I want to achieve.

{
  "values": [
    {
      "id": "1",
      "properties": [
        {
          "stat": "memory",
          "data": 8
        },
        {
          "stat": "cpu",
          "data": 4
        }
      ]
    },
    {
      "id": "2",
      "properties": [
        {
          "stat": "status",
          "data": "OK"
        },
        {
          "stat": "cpu",
          "data": 4
        }
      ]
    }
  ]
}

I want to add a new field to each json object that will have the value of field “stat” as name.

{
  "values": [
    {
      "id": "1",
      "properties": [
        {
          "stat": "memory",
          "data": 8,
          "memory": 8
        },
        {
          "stat": "cpu",
          "data": 4,
          "cpu": 4
        }
      ]
    },
    {
      "id": "2",
      "properties": [
        {
          "stat": "status",
          "data": 0,
          "status": 0
        },
        {
          "stat": "cpu",
          "data": 4,
          "cpu": 4
        }
      ]
    }
  ]
}

I have tried to do the following with JsonPath library but for me it’s an ugly solution as I will parse the json three times and I do some manual replacements.

val configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.ALWAYS_RETURN_LIST).build()
val jsonContext5 = JsonPath.using(configuration).parse(jsonStr)
val listData = jsonContext.read("$['values'][*]['properties'][*]['data']").toString
      .replace("[", "").replace("]", "").split(",").toList
val listStat = jsonContext.read("$['values'][*]['properties'][*]['stat']").toString
      .replace("[", "").replace("]", "")
      .replace(""", "").split(",").toList
// Replacing values of "stat" by values of "data"
jsonContext5.map("$['values'][*]['properties'][*]['stat']", new MapFunction() {
      var count = - 1
      override def map(currentValue: Any, configuration: Configuration): AnyRef = {
        count += 1
        listData(count)
      }
    })
// replace field stat by its value
for( count <- 0 to listStat.size - 1){
     val path = s"['values'][*]['properties'][$count]"
     jsonContext5.renameKey(path, "stat", s"${listStat(count)}")
}
    

This is the result obtained

{
  "values": [
    {
      "id": "1",
      "properties": [
        {
          "data": 8,
          "memory": "8"
        },
        {
          "data": 4,
          "cpu": "4"
        }
      ]
    },
    {
      "id": "2",
      "properties": [
        {
          "data": 0,
          "memory": "0"
        },
        {
          "data": 4,
          "cpu": "4"
        }
      ]
    }
  ]
}

Is there any better method to achieve this result ? I tried to do it with gson but it’s not good handling paths.

This a way to do it with Gson but I will lose the information about other columns since I’m creating another json.

val jsonArray = jsonObject.get("properties").getAsJsonArray
val iter = jsonArray.iterator()
val agreedJson = new JsonArray()
while(iter.hasNext) {
    val json = iter.next().getAsJsonObject
    agreedJson.add(replaceCols(json))
}
def replaceCols(json: JsonObject) = {
    val fieldName = "stat"
    if(json.has(fieldName)) {
      val columnName = json.get(fieldName).getAsString
      val value: String = if (json.has("data")) json.get("data").getAsString else ""
      json.addProperty(columnName, value)
    }
    json
}

Answer

How about something like this?

private static void statDup(final JSONObject o) {
    if (o.containsKey("properties")) {
        final JSONArray a = (JSONArray) o.get("properties");
        for (final Object e : a) {
            final JSONObject p = (JSONObject) e;
            p.put(p.get("stat"), p.get("data"));
        }
    } else {
        for (final Object key : o.keySet()) {
            final Object value = o.get(key);
            if (value instanceof JSONArray) {
                for (final Object e : (JSONArray) value) {
                    statDup((JSONObject) e);
                }
            }
        }
    }
}