[Gson 6]Gsonタイプアダプタ(TypeAdapter)

4621 ワード

TypeAdapterの使用動機
Gsonは、シーケンス化と逆シーケンス化の場合、デフォルトでは、POJOクラスのフィールド属性名とJSONシリアルキーを1つ1つマッピングしてマッチングし、JSONシリアルのキーに対応する値をPOJOと同じフィールドに対応する値に変換し、逆に、この過程で1つのJSONシリアルKeyに対応するValueとオブジェクトとの間でどのように変換(シーケンス化/逆シーケンス化)するかという問題がある.
 
Dateを例にとると、Gsonはシーケンス化と逆シーケンス化の場合にjavaをデフォルトで使用する.text.DateFormatは、Dateオブジェクトを日付文字列にシーケンス化し、日付文字列をDateオブジェクトに逆シーケンス化します.
 
このデフォルトの変換ロジックは、多くの場合、ニーズを満たすことができますが、JSON列では日付のミリ秒数が定義され、POJOではDateタイプが定義されているなど、この変換のロジックをカスタマイズする必要がある場合があります.このタイプ(文字列番号とDate)の変換に適したタイプのアダプタが提供されます.タイプアダプタという拡張機構により,Gsonの利用者は実際の必要に応じてある特定のタイプのシーケンス化と逆シーケンス化の変換を制御することができる.
 
Dateと文字列の日付ミリ秒数が適切です
長い整数文字列を日付タイプでシーケンス化し、逆シーケンス化します(長い整数ミリ秒の列で日付を表します).
 
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Date;

class LongDateTypeAdapter extends TypeAdapter<Date> {
    @Override
    public void write(JsonWriter out, Date value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value(value.getTime());
        }
    }

    @Override
    public Date read(JsonReader in) throws IOException {
        if (in.peek() == null) {
            return null;
        }
        String str = in. nextString();
        Date d  = new Date(Long.parseLong(str));
        return d;
    }
}

class Model {
    private Date date;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

public class Test {

    public static void main(String[] args) {
        Date d = new Date();
        Model m = new Model();
        m.setDate(d);
        Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new LongDateTypeAdapter()).create();
        String str = gson.toJson(m);
        System.out.println(str); //{"date":1407921708088}

        m = gson.fromJson(str, Model.class);
        System.out.println(m.getDate().getTime()); //1407921708088
    }

}

 
前述の例では、Modelオブジェクトを{"date":14079121708088}にシーケンス化し、{"date":14079170708088}を逆シーケンス化してModelオブジェクトにし、GsonはカスタムタイプアダプタLongDateTypeAdapterを介して日付タイプDateとLongを適応した.
数字とEnumタイプの適合
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;

enum Status {
    OK, ERROR, UNKNOWN;
}

class EnumTypeAdapter extends TypeAdapter<Status> {
    @Override
    public Status read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            return null;
        } else {
            int status = in.nextInt();
            if (status == 0) {
                return Status.OK;
            } else if (status == 1) {
                return Status.ERROR;
            } else {
                return Status.UNKNOWN;
            }
        }
    }

    @Override
    public void write(JsonWriter out, Status value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else if (value == Status.OK) {
            out.value(0);
        } else if (value == Status.ERROR) {
            out.value(1);
        } else {
            out.value(2);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().registerTypeAdapter(Status.class, new EnumTypeAdapter()).create();
        String str = gson.toJson(Status.OK);
        System.out.println(str);//0
        Status status = gson.fromJson(str, Status.class);
        System.out.println(status);//OK

    }
}
 
 
Gsonプリ定義アダプタ
Gsonはjavaをデフォルトで使用しています.text.DateFormatは日付と文字列を変換しますが、この変換ロジックはどのように実現されますか?これはGsonプリ定義アダプタDateTypeAdapterを使用しており、Gsonプリ定義アダプタは第7部で分析されています