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

第29回JavaオブジェクトとJSONオブジェクトの変換に便利な「Google Gson」

基本型→JSONの変換

前回は2回にわたってJavaプログラムでJSONデータを扱うための「Jackson Java JSON-processor」を紹介しました。今回はJSONデータを扱うもう1つのJavaライブラリGoogle Gsonを紹介します。Gsonの特徴は、JavaオブジェクトとJSONオブジェクトの変換を、シンプルなコードで行うことができる点です。字句解析を行えるような低レベルのAPIも備えていますが、それよりもオブジェクト変換の簡潔さに注力しているあたりがJacksonとの大きな違いと言えます。

Gsonはこのページよりダウンロードすることができます。⁠google-gson-2.1-release.zip 」をダウンロードして解凍し、中のjarファイルをクラスパスに含めて使用します。

Gsonを使う場合に重要なのは、GsonクラスのtoJson()メソッドとfromJson()メソッドの2つだけです。名前からも推察できるように、toJson()はJavaオブジェクトをJSONオブジェクトに変換するためのメソッド、fromJson()はおの逆にJSONからJavaへ変換するためのメソッドです。

まずは整数や文字列をJSON形式で出力してみましょう。次のようにGsonインスタンスを生成し、toJson()メソッドに整数や文字列を渡すと、JSON形式のテキストが返されます。配列も同様で、基本型の配列であればそのまま渡すだけでJSON配列に変換してくれます。

// Gsonオブジェクトを作成
Gson gson = new Gson();

// 基本型、String、配列からJSONへの変換
System.out.println(gson.toJson(123));        // 「123」と出力
System.out.println(gson.toJson("hello"));    // 「"hello"」と出力
int[] numbers = {1, 2, 3};
System.out.println(gson.toJson(numbers)); // 「[1,2,3]」と出力

toJson()メソッドでJSONデータを直接ファイルに出力することもできます。その場合、メソッドの第2引数にJsonWriterインスタンスを渡せば問題ありません。JsonWriterのコンストラクタには任意のWriterインスタンスを指定できるので、下記のようにここにFileWriterを渡せばいいわけです。ただし、JsonWriterを引数に取るtoJson()メソッドでは基本型を直接扱うことができないので、代わりにJsonPrimitiveクラスを使用する必要があります。

// ファイルへの書き出し
try (JsonWriter writer = 
     new JsonWriter(new BufferedWriter(new FileWriter("output1.json")))) {     
    gson.toJson(new JsonPrimitive("hello"), writer);
} catch (IOException ex) {
    ex.printStackTrace();
}

このコードを実行すると、output1.jsonとして次のようなJSONデータが生成されます。

"hello"

JSON→基本型の変換

JSON形式のデータをJavaオブジェクトとして読み込むにはfromJson()メソッドを利用します。その場合、引数にはJSON形式のStringオブジェクトと、変換後のJavaオブジェクトのClassインスタンスをセットで渡す必要があります。データ基本型や文字列、基本型の配列であれば、次のような具合です。

// Gsonオブジェクトを作成
Gson gson = new Gson();

// JSONから基本型、Stringへの変換
int number = gson.fromJson("123", int.class);
System.out.println(number);  // 「123」と出力
String text = gson.fromJson("\"hello\"", String.class);
System.out.println(text);        // 「hello」と出力
int[] array = gson.fromJson("[1, 2, 3]", int[].class);
System.out.println(array);      // 「[x@xxxx」(配列の文字列表現)と出力

ファイルから読み込む場合には、次のようにJsonReaderクラスを利用します。

// ファイルからの読み込み
try (JsonReader reader = 
     new JsonReader(new BufferedReader(new FileReader("output1.json")))) {     
  text = gson.fromJson(reader, String.class);
  System.out.println(text);       // 「hello」と出力
} catch (IOException ex) {
  ex.printStackTrace();
}

Javaオブジェクト→JSONの変換

次に、任意のJavaオブジェクトをJSON形式に変換して出力してみましょう。ここでは例として、次のようなNameクラスとUserクラスを使用します。NameオブジェクトがUserオブジェクトの要素になっている形です。

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

  public Name(String first, String last) {
    this.first = first;
    this.last = last;
  }
}
public class User {
  private Name name;
  private String mail;

  public User(Name name, String mail) {
    this.name = name;
    this.mail = mail;
  }

  @Override
  public String toString() {
    return "name:\n  " + name.getFirst() + "\n  " + name.getLast() + "\nmail:\n  " + mail;
  }
}

この場合も、先ほどと同様にtoJson()メソッドを利用します。ただし、今度は次のように対象となるJavaオブジェクトのClassインスタンスをセットで渡す必要があります。

// JSONファイルの書き出し
try (JsonWriter writer = 
     new JsonWriter(new BufferedWriter(new FileWriter("output2.json")))) {     
    // UserオブジェクトからJSONへの変換
    Name name = new Name("技評", "太郎");
    User user = new User(name, "taro@example.co.jp");
    gson.toJson(user, User.class, writer);
} catch (IOException ex) {
    ex.printStackTrace();
}

このコードを実行すると、output2.jsonとして次のようなJSONデータが生成されます。オブジェクトのネストも表現できていることがわかります。

{"name":{"first":"技評","last":"太郎"},"mail":"taro@example.co.jp"}

JSON→Javaオブジェクトの変換

続いて今生成したoutput2.jsonをUserオブジェクトとして読み込んでみましょう。これも先ほどと同様に、fromJson()メソッドにJsonReaderインスタンスとUserのClassインスタンスを渡して実行します。

// JSONファイルからの読み込み
try (JsonReader reader = 
     new JsonReader(new BufferedReader(new FileReader("output2.json")))) { 
    // JSONからUserオブジェクトへの変換
    User user = gson.fromJson(reader, User.class);
    System.out.println(user);
} catch (IOException ex) {
    ex.printStackTrace();
}

このコードの実行結果は次のようになり、JSONファイルからUserオブジェクトが生成できていることが確認できます。

name:
  技評
  太郎
mail:
  taro@example.co.jp

Collectionオブジェクト→JSONの変換

複数のオブジェクトからなる配列をJSON形式で作成したい場合にはどうしたらいいでしょうか。その場合はCollectionを利用します。たとえば次のコードは、Integerのデータを持ったArrayListからJSONデータを作成するサンプルです。

// JSONファイルの書き出し
try (JsonWriter writer = 
     new JsonWriter(new BufferedWriter(new FileWriter("output3.json")))) { 
    // CollectionオブジェクトからJSONへの変換
    ArrayList list = new ArrayList();
    list.add(1);
    list.add(2);
    list.add(3);
    gson.toJson(list, ArrayList.class, writer);
} catch (IOException ex) {
    ex.printStackTrace();
}

生成されるoutput3.jsonの中身は、次のような整数オブジェクトの配列になります。

[1,2,3]

ArrayListの中身がIntegerではなくUserオブジェクトの場合も同様です。

// JSONファイルの書き出し
try (JsonWriter writer = 
     new JsonWriter(new BufferedWriter(new FileWriter("output4.json")))) { 
    // 複数のUserからなるCollectionの生成
    Name name1 = new Name("技評", "太郎");
    User user1 = new User(name1, "taro@example.co.jp");
    Name name2 = new Name("技術", "次郎");
    User user2 = new User(name2, "jiro@example.co.jp");

    ArrayList userList = new ArrayList();
    userList.add(user1);
    userList.add(user2);

    // Userを含むCollectionオブジェクトからJSONへの変換
    gson.toJson(userList, ArrayList.class, writer);
} catch (IOException ex) {
    ex.printStackTrace();
}

この場合、output3.jsonの中身は次のようになります(見やすいように改行とスペースを追加しています⁠⁠。UserオブジェクトもJSON形式に正しく展開されていることがわかります。

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

JSON→Collectionオブジェクトの変換

最後に、上で生成したoutput3.jsonおよびoutput4.jsonから、それぞれJavaオブジェクトを生成するプログラムを作ってみます。まずはoutput3.jsonからです。注意すべき点として、Genericsを用いたArrayListは、Classインスタンスをこれまでと同じように表現できないという問題があります。そこで、TypeTokenクラスを利用します。このクラスは型引数として指定した型のjava.lang.reflect.Typeインスタンスを生成してくれまする。

得られたTypeインスタンスを次の例のようにfromJson()に渡すことで、型指定の問題をクリアすることができます。

// JSONファイルからの読み込み
try (JsonReader reader = 
     new JsonReader(new BufferedReader(new FileReader("output3.json")))) { 
    // JSONからCollectionオブジェクトへの変換
    Type type = new TypeToken>(){}.getType();
    ArrayList list = gson.fromJson(reader, type);
    for (Integer i: list) {
        System.out.println(i);
    }
} catch (IOException ex) {
    ex.printStackTrace();
}

このコードの実行結果は次のようになります。配列の要素が個別にIntegerとしてArrayListに格納されていることがわかります。

1
2
3

output4.jsonの場合も同様に、TypeTokenクラスを利用を利用することでArrayListの型を指定できるようになります。

// JSONファイルからの読み込み
try (JsonReader reader = 
     new JsonReader(new BufferedReader(new FileReader("output4.json")))) { 
    // JSONからCollectionオブジェクトへの変換
    Type type = new TypeToken>(){}.getType();
    ArrayList list = gson.fromJson(reader, type);
    for (User user: list) {
        System.out.println(user);
    }
} catch (IOException ex) {
    ex.printStackTrace();
}

このコードの実行結果は次のようになります。配列の要素になっているオブジェクトも、正しくUserオブジェクトに変換されています。

name:
  技評
  太郎
mail:
  taro@example.co.jp
name:
  技術
  次郎
mail:
  jiro@example.co.jp

このように、JSONオブジェクトとJavaオブジェクトの変換を行うという点ではGsonは極めて簡潔で便利なライブラリです。ただし、異なる型のオブジェクトを要素として持つ配列など、複雑なJSONデータの読み込みには低レベルAPIを使わなければならず、ここで紹介したようなシンプルな方法では対応できません。したがって簡潔さではGsonに、柔軟性では前回紹介したJacksonに軍配が上がりそうです。

おすすめ記事

記事・ニュース一覧