Jacksonで直接JSONを組み立てる方法

# はじめに
たまにはJavaのコードを書くか・・（いや業務ではメイン言語ですが）ということで、現在担当している案件で調べたことを投稿します。

皆さんはSpring Framework使っていますか？
最近はNode.jsやRubyなどでサーバーサイドが組まれることも多くなり、またPaaS側にWebAPIを簡単に提供できる仕組みが用意されていたりとでなかなかゴリゴリにJavaで実装するパターンも珍しくなってくるのかなぁと思っていますが、まだまだ現役ということで現在の案件でもJavaのコーディングを進めています。

今回はちょっと珍しい仕様になっていて、SpringFrameworkで組まれたWebAPIで受け取ったJSONをPOJOにマッピングせず、JSONのまま（動的に）加工して別のWebAPIにブリッジするという処理を組むことになり、はて、JacksonでPOJOを使わずにJSONを組むにはどうしたらよかったかなとJavadocを眺めたところ、下記のようにすればよいことがわかりました。

# JacksonでObjectNodeを作る

`ObjectMapper`に`createObjectNode()`というメソッドが用意されていました。
これを使うと、空のJSONオブジェクトを作成することができます。

このオブジェクトに単純な値を追加するときは`put(fieldName, value)`を使用します。
オブジェクト、または配列を追加するときは`set(fieldName, value)`を使用します。

以下例です。

```java
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = mapper.createObjectNode();
root.put("stringValue", "test");
root.set("brankObject", mapper.createObjectNode());
```

# JacksonでArrayNodeを作る

配列を扱う場合は、`ObjectMapper`に`createArrayNode()`というメソッドが用意されていました。
これを使うと、空のJSON配列を作ることができます。
この配列に要素を追加するには、`add(value)`を使用します。

以下例です。

```java
ObjectMapper mapper = new ObjectMapper();
ArrayNode array = mapper.createArrayNode();
array.add("value");
array.add(mapper.createObjectNode());
```

# JSONを組み立てる例

めっちゃ無駄ですが、自力でPOJOからJSONを組み立てるとこうなります。

```java
public class Test {
    public List<Item> items = Arrays.asList(
            new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
            new Item("Item 2","$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly."))));

    public static class Item {
        Item(String name, String price, List<Feature> features) {
            this.name = name;
            this.price = price;
            this.features = features;
        }

        public String name, price;
        public List<Feature> features;
    }

    public static class Feature {
        Feature(String description) {
            this.description = description;
        }

        public String description;
    }
    
    public static void main(String[] args) throws IOException {
        Test test = new Test();

        ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
        ObjectNode root = mapper.createObjectNode();
        ArrayNode items = mapper.createArrayNode();
        for (Item itemsObj : test.items) {
            ObjectNode item = mapper.createObjectNode();
            item.put("name", itemsObj.name);
            item.put("price", itemsObj.price);
            ArrayNode features = mapper.createArrayNode();
            for (Feature featuresObj : itemsObj.features) {
                ObjectNode feature = mapper.createObjectNode();
                feature.put("description", featuresObj.description);
                features.add(feature);
            }
            item.set("features", features);
            items.add(item);
        }
        root.set("items", items);

        System.out.println(mapper.writeValueAsString(root));
        // 結局、出力結果は下記と同じになる
        // System.out.println(mapper.writeValueAsString(test));
    }
}
```

出力結果

```json
{
  "items" : [ {
    "name" : "Item 1",
    "price" : "$19.99",
    "features" : [ {
      "description" : "New!"
    }, {
      "description" : "Awesome!"
    } ]
  }, {
    "name" : "Item 2",
    "price" : "$29.99",
    "features" : [ {
      "description" : "Old."
    }, {
      "description" : "Ugly."
    } ]
  } ]
}
```

# まとめ
パフォーマンスなどはあまり考慮はしていませんが、Java+JacksonでJSONを直接組み上げる時の参考にしてください。