gsonwrapper~gsonによるJava/JSONシリアライゼーション

2019年5月20日

※弊社製オープンソースソフトはオープンソースソフトウェアとしてまとめているので参照されたい。gsonwrapperについての全投稿は/tag/gsonwrapperにある。

Googleのgsonを利用して簡単にJavaオブジェクト/JSONの間の変換・逆変換を行うためのラッパライブラリである。

This is a wrapper library for Google gson(JSON)library. This makes using gson library much easier to convert Java object/JSON (serialize/deserialize). The following are github repositories.

単純な例

使い方は非常に簡単である。以下に単純な例を示す。このラッパライブラリによって、いかに簡単にJavaオブジェクト/JSON間のシリアライズ・デシリアライズが可能であるかを示すものだ。

基本的には、あるクラスFooのオブジェクトをシリアライズ・デシリアライズしたい場合、そのクラスを指定して、シリアライザを作成し、そのserialize/deserializeメソッドを呼び出すだけである。

Just run this simple example unit-test. You can figure out how gsonwrapper can make it easy.

import java.util.*;
import java.util.stream.*;

import org.junit.*;
import static org.junit.Assert.*;

import com.cm55.gson.*;

public class Sample1 {

  @Test
  public void test() {

    // Fooに対するシリアライザを作成する
    Serializer<Foo>serializer = new Serializer<>(Foo.class);

    // JSON文字列
    String json;

    // オブジェクトを作成し、JSON文字列に変換
    {
      Foo foo = new Foo("testString1", "testString2");
      foo.list.add(new Bar(1, 2));
      foo.list.add(new Bar(3, 4));
      json = serializer.serialize(foo);

      assertEquals("{\"list\":[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}],\"str1\":\"testString1\"}", json);
    }

    // JSON文字列からオブジェクトを再構築
    {
      Foo foo = serializer.deserialize(json);
      assertEquals("testString1,null,1,2,3,4", foo.toString());
    }
  }

  public static class Foo {
    List<Bar>list = new ArrayList<>();
    String str1;
    transient String str2;
    Foo(String str1, String str2) {
      this.str1 = str1;
      this.str2 = str2;
    }
    @Override
    public String toString() {
      return str1 + "," + str2 + "," + list.stream().map(b->b.toString()).collect(Collectors.joining(","));
    }
  }

  public static class Bar {
    int a, b;
    Bar(int a, int b) {
      this.a = a;
      this.b = b;
    }
    @Override
    public String toString() {
      return a + "," + b;
    }
  }
}

この例では、シリアライズすると、

{"list":[{"a":1,"b":2},{"a":3,"b":4}],"str1":"testString1"}

というJSON文字列が生成され、このJSON文字列をデシリアライズすると、元のオブジェクトが再構築される。

制限事項

Javaのシリアライゼーションと異なる制限事項としては以下である。

単一のオブジェクトが使い回されていた場合でも、JSON表現上では独立したものになってしまう。

Javaのシリアライゼーションでは、単一のオブジェクトが複数回現れている場合、その「単一である」という状態は保持されるのだが、JSONにはそのような表現が無いため、必ず別々のオブジェクトになってしまう。

これはシリアライゼーション表現としてJSONを使おうが、XMLを使おうが同じことで、そもそもそのような表現の仕組みが無い。

サブクラスを扱えない

先の例で、例えばBarのサブクラスとしてBar1,Bar2を定義し、これをBarの代わりに用いるとする。JSON表現上では問題無いのだが、元のオブジェクトに復帰(デシリアライズ)ときには、Barオブジェクトとして復帰されてしまう。

そのままでは、元のオブジェクトがBar1あるいはBar2であったことを示すものが何も無いからである。これを扱う方法は後述する。

トップレベルがジェネリッククラスである場合を扱えない

先の例では、Fooクラス内部にListというジェネリッククラスがあるが、この場合は問題無い。問題になるのは、トップレベルのクラスがジェネリックの場合である。例えば、

ArrayList<Foo>fooList = new ArrayList<>();

というオブジェクトを扱おうとして、

Serializer<ArrayList<Foo>>serializer = new Serializer<>(ArrayList<Foo>.class);

とすることはできない。そもそも構文エラーになる。これを扱う方法も後述する。