Android Gson 使用詳解

Json 是一種文本形式的數(shù)據(jù)交換格式,比 xml 更為輕量嗡靡。Json 的解析和生成的方式很多,在 Android 平臺上最常用的類庫有 Gson 和 FastJson 兩種,這里要介紹的是 Gson

Gson 的 GitHub 主頁點(diǎn)擊這里:Gson

一精算、Gson的基本用法

1.1、Gson對象

在進(jìn)行序列化與反序列操作前,需要先實(shí)例化一個(gè) com .google.gson.Gson 對象搞动,獲取 Gson 對象的方法有兩種

        //通過構(gòu)造函數(shù)來獲取
        Gson gson = new Gson();
        //通過 GsonBuilder 來獲取躏精,可以進(jìn)行多項(xiàng)特殊配置
        Gson gson = new GsonBuilder().create();

1.2、生成 Json

利用 Gson 可以很方便地生成 Json 字符串鹦肿,通過使用 addProperty 的四個(gè)重載方法

    public static void main(String[] args) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("String", "leavesC");
        jsonObject.addProperty("Number_Integer", 23);
        jsonObject.addProperty("Number_Double", 22.9);
        jsonObject.addProperty("Boolean", true);
        jsonObject.addProperty("Char", 'c');
        System.out.println();
        System.out.println(jsonObject);
    }

addProperty 方法底層調(diào)用的是 add(String property, JsonElement value) 方法矗烛,即將基本數(shù)據(jù)類型轉(zhuǎn)化為了 JsonElement 對象,JsonElement 是一個(gè)抽象類箩溃,而 JsonObject 繼承了 JsonElement 瞭吃,因此我們可以通過 JsonObject 自己來構(gòu)建一個(gè) JsonElement

    public static void main(String[] args) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("String", "leavesC");
        jsonObject.addProperty("Number", 23);
        jsonObject.addProperty("Number", 22.9);
        jsonObject.addProperty("Boolean", true);
        jsonObject.addProperty("Char", 'c');

        JsonObject jsonElement = new JsonObject();
        jsonElement.addProperty("Boolean", false);
        jsonElement.addProperty("Double", 25.9);
        jsonElement.addProperty("Char", 'c');
        jsonObject.add("JsonElement", jsonElement);

        System.out.println();
        System.out.println(jsonObject);
    }

1.3、Json與數(shù)組涣旨、List的轉(zhuǎn)化

Json數(shù)組 與 字符串?dāng)?shù)組

    public static void main(String[] args) {
        //Json數(shù)組 轉(zhuǎn)為 字符串?dāng)?shù)組
        Gson gson = new Gson();
        String jsonArray = "[\"https://github.com/leavesC\",\"http://www.reibang.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";
        String[] strings = gson.fromJson(jsonArray, String[].class);
        System.out.println("Json數(shù)組 轉(zhuǎn)為 字符串?dāng)?shù)組: ");
        for (String string : strings) {
            System.out.println(string);
        }
        //字符串?dāng)?shù)組 轉(zhuǎn)為 Json數(shù)組
        jsonArray = gson.toJson(strings, String[].class);
        System.out.println("\n字符串?dāng)?shù)組 轉(zhuǎn)為 Json數(shù)組: ");
        System.out.println(jsonArray);
    }

Json數(shù)組 與 List

    public static void main(String[] args) {
        //Json數(shù)組 轉(zhuǎn)為 List
        Gson gson = new Gson();
        String jsonArray = "[\"https://github.com/leavesC\",\"http://www.reibang.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";
        List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {
        }.getType());
        System.out.println("\nJson數(shù)組 轉(zhuǎn)為 List: ");
        for (String string : stringList) {
            System.out.println(string);
        }
        //List 轉(zhuǎn)為 Json數(shù)組
        jsonArray = gson.toJson(stringList, new TypeToken<List<String>>() {
        }.getType());
        System.out.println("\nList 轉(zhuǎn)為 Json數(shù)組: ");
        System.out.println(jsonArray);
    }

1.4歪架、序列化與反序列化

Gson 也提供了 toJson()fromJson() 兩個(gè)方法用于轉(zhuǎn)化 Model 與 Json,前者實(shí)現(xiàn)了序列化霹陡,后者實(shí)現(xiàn)了反序列化
首先和蚪,聲明一個(gè) User 類

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    private String name;

    private int age;

    private boolean sex;

    public User(String name, int age, boolean sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }

}

序列化的方法很簡單,調(diào)用 gson 對象的 toJson 方法烹棉,傳入要序列化的對象

    public static void main(String[] args) {
        //序列化
        User user = new User("leavesC", 24, true);
        Gson gson = new Gson();
        System.out.println();
        System.out.println(gson.toJson(user));
    }

反序化的方式也類似

    public static void main(String[] args) {
        //反序列化
        String userJson = "{\"name\":\"leavesC\",\"age\":24,\"sex\":true}";
        Gson gson = new Gson();
        User user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);
    }

二攒霹、屬性重命名

繼續(xù)使用上一節(jié)聲明的 User 類恰聘,根據(jù) User 類聲明的各個(gè)屬性名羹幸,移動(dòng)端的開發(fā)者希望接口返回的數(shù)據(jù)格式即是如下這樣的

{"name":"leavesC","age":24,"sex":true}

如果沒有和服務(wù)器端溝通好或者是 API 改版了,接口返回的數(shù)據(jù)格式可能是這樣的

{"Name":"leavesC","age":24,"sex":true}
{"userName":"leavesC","age":24,"sex":true}

如果繼續(xù)使用上一節(jié)介紹的方法延蟹,那無疑會(huì)解析出錯(cuò)
例如

    public static void main(String[] args) {
        //反序列化
        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";
        Gson gson = new Gson();
        User user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);
    }

name 屬性值解析不到伏社,所以為 null


此時(shí)為了兼顧多種格式的數(shù)據(jù)抠刺,就需要使用 SerializedName 注解
根據(jù) SerializedName 的聲明來看,SerializedName 包含兩個(gè)屬性值洛口,一個(gè)是字符串矫付,一個(gè)是字符串?dāng)?shù)組,而字符串?dāng)?shù)組含有默認(rèn)值

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface SerializedName {
    String value();

    String[] alternate() default {};
}

SerializedName 的作用是為了在序列化或反序列化時(shí)第焰,指導(dǎo) Gson 如果將原有的屬性名和其它特殊情況下的屬性名聯(lián)系起來

例如买优,修改 User 類挺举,為 name 聲明 SerializedName 注解杀赢,注解值為 userName

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    @SerializedName("userName")
    private String name;

    private int age;

    private boolean sex;

}

在序列時(shí),Json 格式就會(huì)相應(yīng)改變

    public static void main(String[] args) {
        //序列化
        User user = new User("leavesC", 24, true);
        Gson gson = new Gson();
        System.out.println();
        System.out.println(gson.toJson(user));
    }

在反序列化時(shí)也一樣湘纵,能夠解析到正確的屬性值

    public static void main(String[] args) {
        //反序列化
        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";
        Gson gson = new Gson();
        User user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);
    }

還有個(gè)問題沒解決脂崔,為了應(yīng)對多種屬性名不一致的情況,難道我們要聲明多個(gè) User 類嗎梧喷?這顯然是不現(xiàn)實(shí)的砌左,所以還需要為 User 類設(shè)置多個(gè)備選屬性名脖咐,這就需要用到 SerializedName 注解的另一個(gè)屬性值 alternate 了。

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    @SerializedName(value = "userName", alternate = {"user_name", "Name"})
    private String name;

    private int age;

    private boolean sex;

}

以下幾種情況都能夠被正確的反序列化

    public static void main(String[] args) {
        //反序列化
        Gson gson = new Gson();
        String userJson = "{\"userName\":\"leavesC\",\"age\":24,\"sex\":true}";
        User user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);

        userJson = "{\"user_name\":\"leavesC\",\"age\":24,\"sex\":true}";
        user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);

        userJson = "{\"Name\":\"leavesC\",\"age\":24,\"sex\":true}";
        user = gson.fromJson(userJson, User.class);
        System.out.println();
        System.out.println(user);
    }

三汇歹、字段過濾

有時(shí)候并不是所有的字段都需要進(jìn)行系列化和反序列化屁擅,因此需要對某些字段進(jìn)行排除,有四種方法可以來實(shí)現(xiàn)這種需求产弹。

3.1派歌、基于@Expose注解

Expose 注解包含兩個(gè)屬性值,且均聲明了默認(rèn)值痰哨。Expose 的含義即為“暴露”胶果,即用于對外暴露字段,serialize 用于指定是否進(jìn)行序列化斤斧,deserialize 用于指定是否進(jìn)行反序列化早抠。如果字段不聲明 Expose 注解,則意味著不進(jìn)行序列化和反序列化操作折欠,相當(dāng)于兩個(gè)屬性值均為 false 贝或。此外,Expose 注解需要和 GsonBuilder 構(gòu)建的 Gson 對象一起使用才能生效锐秦。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Expose {
    boolean serialize() default true;

    boolean deserialize() default true;
}

Expose 注解的注解值聲明情況有四種

    @Expose(serialize = true, deserialize = true)   //序列化和反序列化都生效
    @Expose(serialize = false, deserialize = true)  //序列化時(shí)不生效咪奖,反序列化時(shí)生效
    @Expose(serialize = true, deserialize = false)  //序列化時(shí)生效,反序列化時(shí)不生效
    @Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效酱床,和不寫注解一樣

現(xiàn)在來看個(gè)例子羊赵,修改 User 類

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    @Expose(serialize = true, deserialize = true)   //序列化和反序列化都生效
    private String a;

    @Expose(serialize = false, deserialize = true)  //序列化時(shí)不生效,反序列化時(shí)生效
    private String b;

    @Expose(serialize = true, deserialize = false)  //序列化時(shí)生效扇谣,反序列化時(shí)不生效
    private String c;

    @Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效昧捷,和不寫注解一樣
    private String d;

    private String e;

    public User(String a, String b, String c, String d, String e) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
    }

    @Override
    public String toString() {
        return "User{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                ", e='" + e + '\'' +
                '}';
    }

}

按照如上的注解值,只有聲明了 Expose 注解且 serialize 值為 true 的字段才能被序列化罐寨,只有聲明了 Expose 注解且 deserialize 值為 true 的字段才能被反序列化

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        User user = new User("A", "B", "C", "D", "E");
        System.out.println();
        System.out.println(gson.toJson(user));

        String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";
        user = gson.fromJson(json, User.class);
        System.out.println();
        System.out.println(user.toString());
    }

3.2靡挥、基于版本

Gson 提供了 @Since 和 @Until 兩個(gè)注解基于版本對字段進(jìn)行過濾,@Since 和 @Until 都包含一個(gè) Double 屬性值鸯绿,用于設(shè)置版本號跋破。Since 的意思是“自……開始”,Until 的意思是“到……為止”瓶蝴,一樣要和 GsonBuilder 配合使用毒返。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Since {
    double value();
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Until {
    double value();
}

當(dāng)版本( GsonBuilder 設(shè)置的版本) 大于或等于 Since 屬性值或小于 Until 屬性值時(shí)字段會(huì)進(jìn)行序列化和反序列化操作,而沒有聲明注解的字段都會(huì)加入序列化和反序列操作

現(xiàn)在來看個(gè)例子舷手,修改 User 類

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    @Since(1.4)
    private String a;

    @Since(1.6)
    private String b;

    @Since(1.8)
    private String c;

    @Until(1.6)
    private String d;

    @Until(2.0)
    private String e;

    public User(String a, String b, String c, String d, String e) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
    }

    @Override
    public String toString() {
        return "User{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                ", e='" + e + '\'' +
                '}';
    }

}

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().setVersion(1.6).create();
        User user = new User("A", "B", "C", "D", "E");
        System.out.println();
        System.out.println(gson.toJson(user));

        String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";
        user = gson.fromJson(json, User.class);
        System.out.println();
        System.out.println(user.toString());
    }

3.3拧簸、基于訪問修飾符

訪問修飾符由 java.lang.reflect.Modifier 提供 int 類型的定義,而 GsonBuilder 對象的 excludeFieldsWithModifiers方法接收一個(gè) int 類型可變參數(shù)男窟,指定不進(jìn)行序列化和反序列化操作的訪問修飾符字段
看個(gè)例子

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class ModifierSample {

    public String publicField = "public";

    protected String protectedField = "protected";

    private String privateField = "private";

    String defaultField = "default";

    final String finalField = "final";

    static String staticField = "static";

}
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC).create();
        ModifierSample modifierSample = new ModifierSample();
        System.out.println(gson.toJson(modifierSample));
    }

3.4盆赤、基于策略

GsonBuilder 類包含 setExclusionStrategies(ExclusionStrategy... strategies)方法用于傳入不定長參數(shù)的策略方法贾富,用于直接排除指定字段名或者指定字段類型
看個(gè)例子

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class Strategies {

    private String stringField;

    private int intField;

    private double doubleField;

    public Strategies(String stringField, int intField, double doubleField) {
        this.stringField = stringField;
        this.intField = intField;
        this.doubleField = doubleField;
    }

    @Override
    public String toString() {
        return "Strategies{" +
                "stringField='" + stringField + '\'' +
                ", intField=" + intField +
                ", doubleField=" + doubleField +
                '}';
    }

}
public static void main(String[] args) {
        Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                //排除指定字段名
                return fieldAttributes.getName().equals("intField");
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                //排除指定字段類型
                return aClass.getName().equals(double.class.getName());
            }
        }).create();

        Strategies strategies = new Strategies("stringField", 111, 11.22);
        System.out.println();
        System.out.println(gson.toJson(strategies));

        String json = "{\"stringField\":\"stringField\",\"intField\":111,\"doubleField\":11.22}";
        strategies = gson.fromJson(json, Strategies.class);
        System.out.println();
        System.out.println(strategies);
    }

字段名為 "intField" 和字段類型為 double 的字段都會(huì)被排除掉


setExclusionStrategies 方法在序列化和反序列化時(shí)都會(huì)生效,如果只是想指定其中一種情況下的排除策略或分別指定排除策略弟劲,可以改為使用以下兩個(gè)方法

addSerializationExclusionStrategy(ExclusionStrategy strategy);

addDeserializationExclusionStrategy(ExclusionStrategy strategy);

四祷安、個(gè)性化配置

4.1、輸出 null

對于 Gson 而言兔乞,在序列化時(shí)如果某個(gè)屬性值為 null 的話,那么在序列化時(shí)該字段不會(huì)參與進(jìn)來凉唐,如果想要顯示輸出該字段的話庸追,可以通過 GsonBuilder 進(jìn)行配置

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class Strategies {

    private String stringField;

    private int intField;

    private double doubleField;

}
 public static void main(String[] args) {
        Gson gson = new GsonBuilder()
                .serializeNulls() //輸出null
                .create();
        Strategies strategies = new Strategies(null, 24, 22.333);
        System.out.println();
        System.out.println(gson.toJson(strategies));
 }

4.2、格式化輸出Json

默認(rèn)的序列化后的 Josn 字符串并不太直觀台囱,可以選擇格式化輸出

    public static void main(String[] args) {
        Gson gson = new GsonBuilder()
                .serializeNulls() //輸出null
                .setPrettyPrinting()//格式化輸出
                .create();
        Strategies strategies = new Strategies(null, 24, 22.333);
        System.out.println();
        System.out.println(gson.toJson(strategies));
    }

4.3淡溯、格式化時(shí)間

Gson 也可以對時(shí)間值進(jìn)行格式化

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class Strategies {

    private Date date;

    private Date date2;

    public Strategies(Date date, Date date2) {
        this.date = date;
        this.date2 = date2;
    }

    @Override
    public String toString() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS", Locale.CHINA);
        return "Strategies{" +
                "date=" + simpleDateFormat.format(date) +
                ", date2=" + simpleDateFormat.format(date2) +
                '}';
    }

}

public static void main(String[] args) {
        Gson gson = new GsonBuilder()
                .setPrettyPrinting()//格式化輸出
                .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")//格式
化時(shí)間
                .create();
        Date date = new Date();
        Strategies strategies = new Strategies(date, new Date(date.getTime() + 1000000));
        System.out.println();
        System.out.println(gson.toJson(strategies));

        String json = "{\n" +
                "  \"date\": \"2018-03-17 19:38:50:033\",\n" +
                "  \"date2\": \"2018-03-17 19:55:30:033\"\n" +
                "}";
        System.out.println();
        System.out.println(gson.fromJson(json, Strategies.class));
    }

五、TypeAdapter

TypeAdapter 是一個(gè)泛型抽象類簿训,用于接管某種類型的序列化和反序列化過程咱娶,包含兩個(gè)抽象方法,分別用于自定義序列化和反序列化過程

public abstract void write(JsonWriter var1, T var2) throws IOException;

public abstract T read(JsonReader var1) throws IOException;

下面看個(gè)簡單的例子

/**
 * 作者:chenZY
 * 時(shí)間:2018/3/17 18:32
 * 描述:https://github.com/leavesC
 */
public class User {

    private String name;

    private int age;

    private boolean sex;

    public User() {
    }

    public User(String name, int age, boolean sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }

}

定義 TypeAdapter 的子類 UserTypeAdapter 來接管 User 類的序列化和反序列化過程
這里設(shè)定當(dāng) User 類序列化時(shí) Json 中的Key值都是大寫字母開頭强品,反序列化時(shí)支持“name”和“Name”兩種不同的 Json 風(fēng)格

public class UserTypeAdapter extends TypeAdapter<User> {

    @Override
    public void write(JsonWriter jsonWriter, User user) throws IOException {
        //流式序列化成對象開始
        jsonWriter.beginObject();
        //將Json的Key值都指定為大寫字母開頭
        jsonWriter.name("Name").value(user.getName());
        jsonWriter.name("Age").value(user.getAge());
        jsonWriter.name("Sex").value(user.isSex());
        //流式序列化結(jié)束
        jsonWriter.endObject();
    }

    @Override
    public User read(JsonReader jsonReader) throws IOException {
        User user = new User();
        //流式反序列化開始
        jsonReader.beginObject();
        while (jsonReader.hasNext()) {
            switch (jsonReader.nextName()) {
                //首字母大小寫均合法
                case "name":
                case "Name":
                    user.setName(jsonReader.nextString());
                    break;
                case "age":
                    user.setAge(jsonReader.nextInt());
                    break;
                case "sex":
                    user.setSex(jsonReader.nextBoolean());
                    break;
            }

        }
        //流式反序列化結(jié)束
        jsonReader.endObject();
        return user;
    }

}
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserTypeAdapter()).create();
        User user = new User("leavesC", 24, true);
        System.out.println();
        System.out.println(gson.toJson(user));

        String json = "{\"Name\":\"leavesC\",\"age\":24,\"sex\":true}";
        user = gson.fromJson(json, User.class);
        System.out.println();
        System.out.println(user);
    }

可以看到 User 類按照預(yù)定義的策略來完成序列化和反序列化了


六膘侮、JsonSerializer 和 JsonDeserializer

TypeAdapter 將序列化和反序列操作都接管了過來,其實(shí) Gson 還提供了只接管序列化過程的接口的榛,即 JsonSerializer
看個(gè)例子

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new JsonSerializer<User>() {
            @Override
            public JsonElement serialize(User user, Type type, JsonSerializationContext jsonSerializationContext) {
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("NameHi", user.getName());
                jsonObject.addProperty("Sex", user.isSex());
                jsonObject.addProperty("Age", user.getAge());
                return jsonObject;
            }
        }).create();
        User user = new User("leavesC", 24, true);
        System.out.println();
        System.out.println(gson.toJson(user));
    }

相對應(yīng)的琼了,JsonDeserializer 接口提供了反序列化的接口

public static void main(String[] args) {
        Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new JsonDeserializer<User>() {
            @Override
            public User deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
                JsonObject jsonObject = jsonElement.getAsJsonObject();
                String name = null;
                //同時(shí)支持 userName 和 name 兩種情況
                if (jsonObject.has("userName")) {
                    name = jsonObject.get("userName").getAsString();
                } else if (jsonObject.has("name")) {
                    name = jsonObject.get("name").getAsString();
                }
                int age = jsonObject.get("age").getAsInt();
                boolean sex = jsonObject.get("sex").getAsBoolean();
                return new User(name, age, sex);
            }
        }).create();
        String json = "{\"userName\":\"leavesC\",\"sex\":true,\"age\":24}";
        User user = gson.fromJson(json, User.class);
        System.out.println();
        System.out.println(user);

        json = "{\"name\":\"leavesC\",\"sex\":true,\"age\":24}";
        user = gson.fromJson(json, User.class);
        System.out.println();
        System.out.println(user);
    }

這里有個(gè)比較麻煩的地方,那就是在使用 TypeAdapter 夫晌、JsonSerializerJsonDeserializer 時(shí)雕薪,總需要調(diào)用 registerTypeAdapter 方法進(jìn)行注冊,那有沒有更簡單的注冊方法呢晓淀?
有的所袁,Gosn 還提供了另一個(gè)注解 @JsonAdapter 用于進(jìn)行簡單的聲明

類似于這樣,聲明了 User 類的序列化或反序列化操作由 UserTypeAdapter 完成凶掰,注解的優(yōu)先級高于 registerTypeAdapter 方法

@JsonAdapter(UserTypeAdapter.class)
public class User {

}

七燥爷、TypeAdapterFactory

TypeAdapterFactory 是用于創(chuàng)建 TypeAdapter 的工廠類,通過參數(shù) TypeToken 來查找確定對應(yīng)的 TypeAdapter锄俄,如果沒有就返回 null 并由 Gson 默認(rèn)的處理方法來進(jìn)行序列化和反序列化操作局劲,否則就由用戶預(yù)定義的 TypeAdapter 來進(jìn)行處理

        Gson gson = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {
            @Override
            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
                //如果 Gson 需要與 User 類相關(guān)的 TypeAdapter ,則返回我們自己定義的 TypeAdapter 對象
                if (typeToken.getType().getTypeName().equals(User.class.getTypeName())) {
                    return (TypeAdapter<T>) new UserTypeAdapter();
                }
                //找不到則返回null
                return null;
            }
        }).create();

八奶赠、結(jié)語

這一篇文章好像寫得太長了一點(diǎn)鱼填?Gson 的知識點(diǎn)介紹到這里也差不多了,以后如果還發(fā)現(xiàn)新內(nèi)容的話我會(huì)繼續(xù)補(bǔ)充毅戈,現(xiàn)在就先這樣啦

公眾號:字節(jié)數(shù)組苹丸,熱衷于分享 Android 系統(tǒng)源碼解析愤惰,Jetpack 源碼解析、熱門開源庫源碼解析等面試必備的知識點(diǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赘理,一起剝皮案震驚了整個(gè)濱河市宦言,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌商模,老刑警劉巖奠旺,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異施流,居然都是意外死亡响疚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門瞪醋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忿晕,“玉大人,你說我怎么就攤上這事银受〖危” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵宾巍,是天一觀的道長咕幻。 經(jīng)常有香客問我,道長蜀漆,這世上最難降的妖魔是什么谅河? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮确丢,結(jié)果婚禮上绷耍,老公的妹妹穿的比我還像新娘。我一直安慰自己鲜侥,他們只是感情好褂始,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著描函,像睡著了一般崎苗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舀寓,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天胆数,我揣著相機(jī)與錄音,去河邊找鬼互墓。 笑死必尼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播判莉,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼豆挽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了券盅?” 一聲冷哼從身側(cè)響起帮哈,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锰镀,沒想到半個(gè)月后娘侍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泳炉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年私蕾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胡桃。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖磕潮,靈堂內(nèi)的尸體忽然破棺而出翠胰,到底是詐尸還是另有隱情,我是刑警寧澤自脯,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布之景,位于F島的核電站,受9級特大地震影響膏潮,放射性物質(zhì)發(fā)生泄漏锻狗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一焕参、第九天 我趴在偏房一處隱蔽的房頂上張望轻纪。 院中可真熱鬧,春花似錦叠纷、人聲如沸刻帚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崇众。三九已至,卻和暖如春航厚,著一層夾襖步出監(jiān)牢的瞬間顷歌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工幔睬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留眯漩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓溪窒,卻偏偏與公主長得像坤塞,于是被迫代替她去往敵國和親冯勉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容