Jackson あるいは、Google gson を使用して
JSON → JavaクラスObject → 属性値の変更 → JavaクラスObject → JSON
という流れを組むのがほとんどの方法であるが、
そうではなく!
Jackson でJSONを読み込んだ結果の 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);
とすれば、可能である。