いろいろガンガンいこうぜ。体も大事に

普段はJavaでAndroidアプリ開発しているプログラマーのブログです。

Gsonのユーザーガイドを見てみた (3)

前回,前々回に引き続き,Gsonのユーザーガイドを見ていきます。



Person.java

package com.rmstar.gson.userguide;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return String.format("%s %d才", name, age);
    }
}

サンプルとして,このクラスを使います。





JSONの表示フォーマット.単純な形式と分かりやすい形式
package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.util.ArrayList;
import java.util.List;

public class PrettyPrinting {
    public static void main(String[] args) {
        Gson gson;

        Person person = new Person("Alice", 25);

        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Taro", 20));
        personList.add(new Person("Jiro", 17));
        personList.add(new Person("Saburo", 14));

        System.out.println("===Compact===");
        gson = new Gson();
        System.out.println(gson.toJson(person));
        System.out.println(gson.toJson(personList));

        System.out.println();

        System.out.println("===Pretty Printing===");
        gson = new GsonBuilder().setPrettyPrinting().create();
        System.out.println(gson.toJson(person));
        System.out.println(gson.toJson(personList));
    }
}

実行結果は,

===Compact===
{"name":"Alice","age":25}
[{"name":"Taro","age":20},{"name":"Jiro","age":17},{"name":"Saburo","age":14}]

===Pretty Printing===
{
  "name": "Alice",
  "age": 25
}
[
  {
    "name": "Taro",
    "age": 20
  },
  {
    "name": "Jiro",
    "age": 17
  },
  {
    "name": "Saburo",
    "age": 14
  }
]


となります。

new Gson().toJson(object)

として生成したGsonでの出力文字列は,空白も改行もありません。

new GsonBuilder().setPrettyPrinting().create().toJson(object)

一方で,GsonBuilderを用いてGsonクラスのインスタンスを生成し,
setPrettyPrinting()を行った後にGson型のインスタンスを生成すれば,
上記のように空白が挿入されたり改行付きで表示されたりします。



nullオブジェクトのサポート
package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class NullObjectSupport {
    public static void main(String[] args) {

        Person person = new Person(null, 20);
        Gson gson;

        gson = new Gson();
        System.out.println(gson.toJson(person));

        gson = new GsonBuilder().serializeNulls().create();
        System.out.println(gson.toJson(person));
    }
}

実行結果

{"age":20}
{"name":null,"age":20}

普通にGsonを用いた場合はnullのフィールドは無視されます。
nullを出力したい場合は,
Gsonクラスをインスタンス化する際,

new GsonBuilder().serializeNulls().create()

とすれば,nullは無視されなくなります。



バージョニング
package com.rmstar.gson.userguide;

import com.google.gson.annotations.Since;

public class VersionedObject {
    private final String v1;

    @Since(2)
    private final String v2;

    @Since(3)
    private final String v3;

    public VersionedObject() {
        v1 = "version1";
        v2 = "version2";
        v3 = "version3";
    }
}

各フィールドに@Sinceアノテーションを上記のように記述して,

package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class VersioningSupport {
    public static void main(String[] args) {
        Gson gson;
        VersionedObject object = new VersionedObject();

        gson = new Gson();
        System.out.println(gson.toJson(object));

        gson = new GsonBuilder().setVersion(1).create();
        System.out.println(gson.toJson(object));

        gson = new GsonBuilder().setVersion(2).create();
        System.out.println(gson.toJson(object));

        gson = new GsonBuilder().setVersion(3).create();
        System.out.println(gson.toJson(object));
    }
}

上記のように,gsonをインスタンス化すれば,

{"v1":"version1","v2":"version2","v3":"version3"}
{"v1":"version1"}
{"v1":"version1","v2":"version2"}
{"v1":"version1","v2":"version2","v3":"version3"}

実行結果はこのようになります。

@Sinceアノテーションを用いれば,
同じオブジェクト・コードでバージョンによる差異を上手に扱えるみたいです。

もしGsonのインスタンスにバージョンの設定がされていないのであれば,
バージョンに関わらず全てのフィールドがシリアライズ・デシリアライズされるようです。


@Sinceアノテーションはクラスに設定することもできるようです。

package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Since;

import java.util.ArrayList;
import java.util.List;

public class VersioningSupport {

    private static class V1 {
        final String v = "version1";
    }

    @Since(2)
    private static class V2 {
        final String v = "version2";
    }

    @Since(3)
    private static class V3 {
        final String v = "version3";
    }

    public static void main(String[] args) {
        Gson gson;

        List<Object> list = new ArrayList<Object>();
        list.add(new V1());
        list.add(new V2());
        list.add(new V3());

        System.out.println("===Version1===");
        gson = new GsonBuilder().setVersion(1).create();
        System.out.println(gson.toJson(list));

        System.out.println("===Version2===");
        gson = new GsonBuilder().setVersion(2).create();
        System.out.println(gson.toJson(list));

        System.out.println("===Version3===");
        gson = new GsonBuilder().setVersion(3).create();
        System.out.println(gson.toJson(list));
    }
}

実行結果は,

===Version1===
[{"v":"version1"},null,null]
===Version2===
[{"v":"version1"},{"v":"version2"},null]
===Version3===
[{"v":"version1"},{"v":"version2"},{"v":"version3"}]

となりました。





フィールドのネーミング
package com.rmstar.gson.userguide;

public class Animal {
    private final String mName;
    private final int mWeight;

    public Animal(String name, int weight) {
        mName = name;
        mWeight = weight;
    }

}

このようなクラスがあったとして,

package com.rmstar.gson.userguide;

import com.google.gson.Gson;

public class JSONFieldNamingSupport {
    public static void main(String[] args) {
        Animal pochi = new Animal("Pochi", 35);
        System.out.println(new Gson().toJson(pochi));
    }
}

この様にGsonを使うと,

{"mName":"Pochi","mWeight":35}

こうなります。
命名規約などでフィールドにmをつけなくてはいけない場合,
Gsonでの出力にもmがついてしまいます。



Animalクラスを次の用に書き換えます。

package com.rmstar.gson.userguide;

import com.google.gson.annotations.SerializedName;

public class Animal {
    @SerializedName("name")
    private final String mName;

    @SerializedName("weight")
    private final int mWeight;

    public Animal(String name, int weight) {
        mName = name;
        mWeight = weight;
    }

}

実行結果は以下のようになりました。

{"name":"Pochi","weight":35}

クラスのフィールド名は元のままですが,GsonでのJSON形式の文字列はmを取ることが出来ました。



シリアライズ・デシリアライズでのフィールドの除外

Gsonではシリアライズ・デシリアライズにおいて,
クラス・フィールド・ある型のフィールドを除外するための多くの仕組みが準備されています。




まずは,修飾子単位での除外

シリアライズの対象は以下のようなクラス。

package com.rmstar.gson.userguide;

public class Example1 {
    private String v0;
    static String v1;
    volatile String v2;
    transient String v3;
    static final String v4;

    static {
        v1 = "static";
        v4 = "constant";
    }

    public Example1() {
        v0 = "private";
        v2 = "volatile";
        v3 = "transient";
    }
}

これを普通にGsonを用いてシリアライズした場合,

{"v0":"private","v2":"volatile"}

となります。
static修飾子とtransient修飾子がついたフィールドは,無視されます。

無視したい修飾子を設定したい場合だとか,
逆にstaticなフィールドを無視したくない場合は,
GsonBuilderでGsonインスタンスを作成する際,
以下のように無視する修飾子を設定することが可能です。

package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.lang.reflect.Modifier;

public class ExcludingFields1 {
    public static void main(String[] args) {
        Gson gson;
        Example1 ex1 = new Example1();

        System.out.println("===Exclude Private===");
        gson = new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.PRIVATE)
                .create();
        System.out.println(gson.toJson(ex1));

        System.out.println("===Exclude Static===");
        gson = new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.STATIC)
                .create();
        System.out.println(gson.toJson(ex1));

        System.out.println("===Exclude Volatile and Transient===");
        gson = new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.VOLATILE | Modifier.TRANSIENT)
                .create();
        System.out.println(gson.toJson(ex1));

        System.out.println("===Exclude Constant===");
        gson = new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC)
                .create();
        System.out.println(gson.toJson(ex1));
    }
}

実行結果は,以下の通りです。

===Exclude Private===
{"v1":"static","v2":"volatile","v3":"transient","v4":"constant"}
===Exclude Static===
{"v0":"private","v2":"volatile","v3":"transient"}
===Exclude Volatile and Transient===
{"v0":"private","v1":"static","v4":"constant"}
===Exclude Constant===
{"v0":"private","v2":"volatile","v3":"transient"}




次に,@Exposeアノテーションを用いての除外
@Exposeアノテーションフィールを用いれば,
フィールド単位でシリアライズ・デシリアライズするフィールドを指定出来ます。

Gsonのインスタンス化を

new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();

のように行った場合,
@Exposedアノテーションがついたフィールドのみ
シリアライズ・デシリアライズされます。

package com.rmstar.gson.userguide;

import com.google.gson.annotations.Expose;

public class Example2 {
    @Expose
    private final String expose;

    private final String notExpose;

    public Example2() {
        expose = "expose";
        notExpose = "not expose";
    }
}

このようなクラスをシリアライズします。

package com.rmstar.gson.userguide;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class ExcludingFields2 {
    public static void main(String[] args) {
        Gson gson;
        Example2 ex2 = new Example2();

        gson = new Gson();
        System.out.println(gson.toJson(ex2));

        gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        System.out.println(gson.toJson(ex2));
    }
}


実行結果は,以下のようになります。

{"expose":"expose","notExpose":"not expose"}
{"expose":"expose"}




独自に定義するExclusion Strategyによる除外を紹介します。

package com.rmstar.gson.userguide;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class MyExclusionStrategy implements ExclusionStrategy {
    private final Class<?> mTypeToSkip;

    public MyExclusionStrategy(Class<?> typeToSkip) {
        mTypeToSkip = typeToSkip;
    }

    @Override
    public boolean shouldSkipClass(Class<?> arg0) {
        return (arg0.equals(mTypeToSkip));
    }

    @Override
    public boolean shouldSkipField(FieldAttributes arg0) {
        return false;
    }
}

このようにExclusionStrategyインターフェースを実装したクラスを独自で定義して,

package com.rmstar.gson.userguide;

import com.google.gson.ExclusionStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class ExcludingFields3 {
    public static void main(String[] args) {
        Person person = new Person("Alice", 25);
        ExclusionStrategy strategy;
        Gson gson;

        strategy = new MyExclusionStrategy(String.class);
        gson = new GsonBuilder()
                .addSerializationExclusionStrategy(strategy)
                .create();
        System.out.println(gson.toJson(person));

        strategy = new MyExclusionStrategy(int.class);
        gson = new GsonBuilder()
                .addSerializationExclusionStrategy(strategy)
                .create();
        System.out.println(gson.toJson(person));
    }
}

実行結果は,以下の通りです。

{"age":25}
{"name":"Alice"}






これでも出来ない場合は,自分で細かくカスタマイズすることもできるようです。
それはまた次回にでも。



それでは,また会えることを祈りつつ。