JSONとマップする任意クラスを定義しないでJSONの値を変更

Jackson あるいは、Google gson を使用して
JSONJavaクラスObject → 属性値の変更 → JavaクラスObject → JSON
という流れを組むのがほとんどの方法であるが、
そうではなく!
JacksonJSONを読み込んだ結果の JsonNode
変更して、toString() や、ObjectMapper の writeValueAsString または、
ObjectWriter で結果を出力する。

先日作成した、
Jackson JSON読込み、key-value 解析を柔軟にする - Oboe吹きプログラマの黙示録
の、JsonNodeParse に、以下のメソッドを追加すれば、
Consumer で、変更の操作が可能である。

public Stream<Entry<String, JsonNode>> nodeStream(JsonNode node){
   Stream.Builder<Entry<String, JsonNode>> builder = Stream.builder();
   nodeJson(node, "", builder);
   return  builder.build();
}
private void nodeJson(JsonNode node, String path, Stream.Builder<Entry<String, JsonNode>> builder){
   if(node.getNodeType().equals(JsonNodeType.OBJECT)) {
      for(Iterator<Entry<String, JsonNode>> it=node.fields(); it.hasNext();) {
         Entry<String, JsonNode> entry = it.next();
         String _path = path + "." + entry.getKey();
         builder.add(new SimpleEntry<String, JsonNode>(_path.substring(1), node));
         nodeJson(entry.getValue(), path + "." + entry.getKey(), builder);
      }
   }else if(node.getNodeType().equals(JsonNodeType.ARRAY)){
      if (node.size() > 0){
         int x=0;
         for(Iterator<JsonNode> it=node.iterator(); it.hasNext();x++){
            nodeJson(it.next(), path + "[" + x + "]", builder);
         }
      }
   }
}

Stream として返す Entry<String, JsonNode> は、JSONキーのパスと
キーのObjectを持つ JsonNode である。

サンプル

{
   "id": 201,
   "buckets":[
      {
         "item": "Lemon",
         "price" : 210
      },
      {
         "item": "orange",
         "price" : 310
      },
      {
         "item": "kiwi",
         "price" : 138
      }
   ]
}

このJSONで、buckets 配列2個目の "item": "orange" を "Apple" に変更する。

// JSON テキスト読込→ JsonNode 変換
ObjectMapper mapper = new ObjectMapper();
JsonNode jnode = mapper.readTree(jsonstr);
// JsonNodeParse 追加したメソッド nodeStream で処理
JsonNodeParse jparse = new JsonNodeParse();
jparse.nodeStream(jnode)
.filter(e->e.getKey().equals("buckets[1].item"))
.forEach(e->{
   String[] pa = e.getKey().split("\\.");
   ((ObjectNode)e.getValue()).put(pa[pa.length-1], "Apple");
   // もしくは、 ((ObjectNode)e.getValue()).put("name", "Apple");
});

// 変更後のJSON
String result = mapper.writeValueAsString(jnode);

変更後のJSONは、、、

{
   "id": 201,
   "buckets":[
      {
         "item": "Lemon",
         "price" : 210
      },
      {
         "item": "Apple",
         "price" : 310
      },
      {
         "item": "kiwi",
         "price" : 138
      }
   ]
}

(補足)
Consumer の Entry<String, JsonNode> JsonNode は、ObjectNode として
put の他に、削除は、

public JsonNode remove(String fieldName)
public JsonNode remove(String fieldName)
public ObjectNode remove(Collection<String> fieldNames)
public ObjectNode removeAll()

がある。
Consumer で行いJsonNodeの操作として、配列を追加セットする場合は、
ArrayNode として作成して set(JsonNode) でセットする

ObjectMapper mapper = new ObjectMapper();
List<String> list = new ArrayList<>();
list.add("A");list.add("B");
ArrayNode array = mapper.valueToTree(list);
((ObjectNode)e.getValue()).set("list", array);

とすれば、可能である。