はじめに

この記事は、JavaでREST APIや設定ファイルを扱っていて「JacksonのJsonNodeに新しいプロパティを追加・上書きしたいけど、やり方がいまいち分からない」という中級者の方を対象にしています。
記事を読むことで、ObjectNodeとArrayNodeの違いを理解し、put()set()add()メソッドを使ってJsonNodeに値をセットできるようになります。実装でよくハマる「不変のJsonNodeに追加しようとして例外が出る」問題も、原因と回避策をあわせて解説します。

前提知識

  • Java 11以降の基本的な文法
  • JacksonでJSONを読み込み、JsonNodeとして取得できること
  • Maven/Gradleでjackson-databindが依存に含まれていること

JacksonでJsonNodeを更新する必要性

Jacksonは、JSONをツリー型のJsonNodeとして扱えるため、フィールド名が動的に変わるようなケースでも便利です。ただし、読み取り専用のJsonNodeをそのまま変更しようとするとUnsupportedOperationExceptionが発生します。
そこで、読み書き可能なObjectNode/ArrayNodeに変換してから値をセットする手法を押さえておくことが、堅牢なJSON加工の第一歩になります。

ステップバイステップ:JsonNodeに値をセットする

ステップ1:ObjectNodeにプロパティを追加・上書きする

まず、JSON文字列を読み込み、新規プロパティを追加してみます。

Java
ObjectMapper mapper = new ObjectMapper(); ObjectNode root = (ObjectNode) mapper.readTree(""" {"name":"taro","age":20} """); root.put("email", "taro@example.com"); // 文字列追加 root.put("age", 25); // 数値上書き root.set("address", mapper.createObjectNode() // オブジェクト追加 .put("zip", "150-0001") .put("city", "Shibuya")); System.out.println(root.toPrettyString());

出力例

Json
{ "name" : "taro", "age" : 25, "email" : "taro@example.com", "address" : { "zip" : "150-0001", "city" : "Shibuya" } }

ステップ2:ArrayNodeに要素を追加する

次に、配列を扱います。add()で末尾に追加、set(index, node)で上書きが可能です。

Java
ArrayNode hobbies = mapper.createArrayNode() .add("soccer") .add("music"); hobbies.add("programming"); // 末尾追加 hobbies.set(1, mapper.valueToNode("guitar")); // 1番目を上書き root.set("hobbies", hobbies);

配列の要素もJsonNodeでラップするため、プリミティブ型はvalueToNode()で変換すると便利です。

よくあるエラー:UnsupportedOperationException

読み取り専用のJsonNodeを直接更新しようとすると、以下のような例外が出ます。

Exception in thread "main" java.lang.UnsupportedOperationException:
   Not an ObjectNode

これは、JsonNodeが不変であるためです。必ずObjectNode/ArrayNodeにキャストするか、createObjectNode()/createArrayNode()で新規作成してから操作してください。

解決策:不変を回避する3パターン

  1. 読み取り専用ノードをコピーする
    ObjectNode editable = root.deepCopy();

  2. 新規作成してから差し替える
    ObjectNode editable = mapper.createObjectNode();

  3. 読み込み時点からObjectNodeとして受ける
    ObjectNode root = mapper.readValue(json, ObjectNode.class);

どのパターンでも、操作後にtoPrettyString()でログ出力するとデバッグが捗きます。

まとめ

本記事では、JacksonのJsonNodeに値をセットする方法を解説しました。

  • ObjectNodeならput()/set()でプロパティ追加・上書き
  • ArrayNodeならadd()/set(index,node)で要素操作
  • 読み取り専用ノードはコピーor新規作成してから変更

この知識があれば、設定ファイルの差分更新や、REST APIレスポンスの動的な書き換えが安全に行えます。次回は、JsonNodeをJavaオブジェクトに戻す(デシリアライズ)テクニックについて深掘りします。

参考資料