Help us understand the problem. What is going on with this article?

Gsonで変換専用のクラスを作らずにJSONを読み書きする(JSONICの場合のおまけつき)

More than 5 years have passed since last update.

Gsonは基本的にJSONとJavaオブジェクトを相互に変換するライブラリです。

しかし、変換のための専用クラスを作成しなくてもJSONを読み書きすることができます。

使用頻度が低いJSONや、JSONの中身がかなり不定形でクラスに切り出しにくいなどで、変換のためのクラスを作成したくないときに、使えると思います。

(結論をいえば、結局は基本的に変換専用のPOJOを作った方がよさそうです。どうしても変換専用のクラスを作りたくないなら、JSONICの方が読みやすいコードになるかもしれません)

JSON編集

下のように配列やネスト構造も作れます。

{
    "outer_name": "outer_value",
    "inner": {
        "inner_name": "inner_value",
        "inner_array": [
            "abc", 
            123, 
            true
        ]
    }
}

このJSONを出力するコードは次の通りです。
(上記の例の改行とスペースは見やすさのために加えたものです。実際は改行もスペースもありません)

Writerを使う方法

StringWriter stringWriter = new StringWriter();
JsonWriter gsonWriter = new JsonWriter(new BufferedWriter(stringWriter));
gsonWriter.beginObject();
gsonWriter.name("outer_name").value("outer_value");
gsonWriter.name("inner");
gsonWriter.beginObject();
gsonWriter.name("inner_name").value("string_inner_value");
gsonWriter.name("inner_name").beginArray().value("abc").value("def").value("ghi").endArray();
gsonWriter.endObject();
gsonWriter.endObject();
gsonWriter.close();

String json = new String(stringWriter.getBuffer());
System.out.println(json);

参考:http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonWriter.html

JsonObjectを使う方法

JsonObject root = new JsonObject();
root.addProperty("outer_name", "outer_value");
JsonObject inner = new JsonObject();
inner.addProperty("inner_name", "inner_value");
JsonArray innerArray = new JsonArray();
innerArray.add(new JsonPrimitive("abc"));
innerArray.add(new JsonPrimitive(123));
innerArray.add(new JsonPrimitive(true));
inner.add("inner_array", innerArray);
root.add("inner", inner);

String json2 = new Gson().toJson(root);
System.out.println(json2);

JSON読込

Readerを使う方法

茨の道だったので敢えて紹介しません。
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.htmlが参考になります。

JsonObjectを使う方法

編集のところで作成したJSONを読み込んで、一番上の階層のouter_nameの値を取り出すコードは次のようになります。

JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
String firstElement = jsonObject.get("outer_name").getAsString();
System.out.println(firstElement);

inner_arrayの配列の先頭の要素を取り出すコードは次のようになります

JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
JsonObject innter = jsonObject.get("inner").getAsJsonObject();
String firstElement = inner.getAsJsonArray("inner_array").get(0).getAsString();
System.out.println(firstElement);

感想

編集の感想

どちらの方法も、JSONの階層構造がコードの見た目にあまり現れていない点で、読みづらいですね。
特別な理由がない限り、変換専用のオブジェクトを作ろうと思いました。
もしくは上手にラッパークラスを作ればイケるかも、いや、冷静に考えるとあまりやりたくないかな?くらいの実用度だと思います。

読込の感想

編集に比べればそこそこマシだと思います。

GsonではなくJSONICというライブラリなら

StringBuilder stringBuilder = new StringBuilder();
JSONWriter jsonicWriter = new JSON().getWriter(stringBuilder);
jsonicWriter.beginObject();
jsonicWriter.name("outer_name").value("outer_value");
jsonicWriter.name("inner").value(new Object() {
    public String inner_name = "inner_value";
    public Object[] inner_array = { "abc", 123, true };
});
jsonicWriter.endObject();

String json = new String(stringBuilder);
System.out.println(json);

という具合にネスト構造を匿名クラスとして表現できて、
さらに、ネストのネストは、匿名クラスの中の匿名クラスで……という調子にオブジェクトの構造でJSONの構造を現せます。
JSONの構造をコードに現しやすいという点ではより優れていると思います。
(まだまだ煩雑ですが……)

JSONICの場合の読み込みはこんな感じです。
Gsonと同じく、ネストの中の配列の先頭の要素を取り出しています。

JSONReader reader = new JSON().getReader(json3);
reader.next();
Map<?, ?> map = reader.getMap();
Map jsonicInner = (Map) map.get("inner");
List array = (List) jsonicInner.get("inner_array");

System.out.println(array.get(0));

MapやListになるので、Gsonの場合よりもわかりやすい感じがしますね。

結論

  • 基本に忠実に、POJO <-> JSON で変換した方がよさげ
  • どうしても変換専用のクラスを作りたくないならGsonよりもJSONICの方が可読性が高い気がする
arai-wa
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away