本格派エンジニアの工具箱

第28回 「Jackson Java JSON-processor」でJSONデータの読み書きを行う

この記事を読むのに必要な時間:およそ 3.5 分

ツリーモデルAPIでJSONデータを書き出す

続いて,データの書き出しを行ってみましょう。先ほども書きましたが,ノードの種類は配列やオブジェクト,各型の値などによって,JsonNodeを継承する次のようなクラスで定義されています。このうち,BinaryNode以下は値を表すノードで,全てValueNodeのサブクラスとなっています。

  • ArrayNode
  • ObjectNode
  • BinaryNode
  • BooleanNode
  • NumericNode
  • POJONode
  • TextNode
  • NullNode

ArrayNodeにノードや値を追加するには,add()またはaddXxxx()メソッドを使用します。addXxxx()メソッドは新規にArrayNodeやObjectNodeを作成して追加するためのメソッドで,追加したノードオブジェクトを戻り値として返します。たとえば次のように記述した場合,rootNodeにはObjectNodeが新規に追加され,firstObjectにはそのObjectNodeが返されます。

ObjectNode firstObject = rootNode.addObject();

ObjectNodeにノードや値を追加する場合には,putまたはputXxxx()メソッドを使用します。ArrayNodeの場合と同様に,putXxxx()メソッドでは新規にArrayNodeやObjectNodeを作成して追加するためのメソッドです。ただし,addXxxx()と異なり,引数にはフィールド名を指定する必要があります。たとえば次のように記述した場合,firstObjectには「name」というフィールド名を持ったObjectNodeが新規に追加され,nameObject1にはそのObjectNodeが返されます。

ObjectNode nameObject1 = firstObject.putObject("name");

起点となるノードは,ObjectMapperのcreateArrayNode()メソッドやcreateObjectNode()メソッドを使って生成できます。

// ルートノードを配列として作成する場合
ArrayNode rootNode = mapper.createArrayNode();

// ルートノードを配列として作成する場合
ObjectNode rootNode = mapper.createObjectNode();

作成したJSONデータをファイルへ出力するにはObjectMapperのwrite()メソッドを使います。このメソッドにノードオブジェクトを渡すと,それ以下のノードのデータが指定されたファイルや出力ストリームに書き出されます。

mapper.writeValue(new File("output.json"), rootNode);

以上を踏まえて,次のようなJSONデータを生成するプログラムを考えてみましょう。

[{
  "name":{"first":"太郎","last":"技評"},
  "mail":"taro@example.co.jp"
},{
  "name":{"first":"次郎","last":"技術"},
  "mail":"jiro@example.co.jp"
}]

ネストを含む複数のオブジェクトが配列に格納されている形のデータです。これは次のようなコードで生成できます。

// ObjectMapperを作成
ObjectMapper mapper = new ObjectMapper();
    
// ルートノードを配列として作成
ArrayNode rootNode = mapper.createArrayNode();

// 「技評太郎」のデータを追加
ObjectNode firstObject = rootNode.addObject();
ObjectNode nameObject1 = firstObject.putObject("name");
nameObject1.put("first", "太郎");
nameObject1.put("last", "技評");
firstObject.put("email", "taro@example.jp");

// 「技術次郎」のデータを追加
ObjectNode secondObject = rootNode.addObject();
ObjectNode nameObject2 = firstObject.putObject("name");
nameObject2.put("first", "次郎");
nameObject2.put("last", "技術");
secondObject.put("mail", "jiro@example.jp");

// ファイルへ書き出し
try {
    mapper.writeValue(new File("output.json"), rootNode);
} catch (IOException ex) {
    ex.printStackTrace();
}

Javaオブジェクトとのバインディングもサポート

Jacksonには,ストリーミングAPIとツリーモデルAPIの他に,JavaオブジェクトとのバインディングによってJSONデータの読み書きを行うAPIも用意されています。バインディングAPIは,MapやArrayList,StringといったJavaの既存の型に関連付けられるものと,任意のJavaオブジェクト(Java Beanオブジェクト)に関連付けられるものの2種類があります。

前者の場合,JSONのデータ型とJavaのクラスは次の表のように関連付けられます。

JSONの型Javaのクラス
オブジェクトLinkedHashMap<String,Object>
配列ArrayList<Object>
文字列String
整数Integer, Long, BigInteger
浮動小数点数Double(設定によってBigDecimalを使用することも可)
true/falseBoolean
nullnull

後者の場合,任意のJavaクラスのオブジェクトをJSONデータに変換することが可能です。たとえばUserクラスおよびNameクラスが次のように定義されているとします。

public class User {
    private Name name;
    private String mail;
    ......
}

public class Name {
    private String first;
    private String last;
    ......
}

このとき,UserオブジェクトはObjectMapperクラスを利用してJSONデータとして出力することができます。出力方法はJsonNodeの場合と同様です。

Name name = new Name("太郎", "技評");
User user = new User(name1, "taro@example.co.jp");

mapper.writeValue(new File("output.json"), user);

このように,Jacksonでは複数の方法によるJSONデータの読み書きがサポートされているので,用途に応じて使い分けられるという点が大きなメリットになっています。

著者プロフィール

杉山貴章(すぎやまたかあき)

ONGS Inc.所属のプログラマ兼テクニカルライター。雑誌,書籍,Webメディアで多数の著作をもつ。

著書