Android中詳盡的Gson(可能有你沒(méi)用過(guò)的方式)

Gson使用

項(xiàng)目地址:https://github.com/google/gson

實(shí)例化Gson對(duì)象

  1. 通過(guò)構(gòu)造函數(shù)獲取

    Gson gson = new Gson();

  2. 通過(guò)GsonBuilder獲取取试,可以進(jìn)行多項(xiàng)配置

    Gson gson = new GsonBuilder().create();

生成Json字符串

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name","hyf");
jsonObject.addProperty("age",21);
jsonObject.addProperty("Boolean",true);

JsonElement

JsonObject jsonObject = new JsonObject();
Json.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);

Json和數(shù)組/List轉(zhuǎn)換

1. json轉(zhuǎn)字符串?dāng)?shù)組
Gson gson = new Gson();
String jsonArray = "[\"3\",\"4\",\"5\"]";
String[] strings = gson.fromJson(jsonArray,String[].class);
2. 字符串?dāng)?shù)組轉(zhuǎn)json
String jsonArray = gson.toJson(jsonArray,new TypeToken<String>(){}.getType());
3. json轉(zhuǎn)List
String jsonArray = "[....]"  //此處jsonArray與(1)中相同
List<String> stringList = gson.fromJson(jsonArray,new TypeToken<List<String>>(){}.getType());
4. List轉(zhuǎn)Json
String jsonArray = gson.toJson(stringList,new TypeToken<List<String>>(){}.getType());

序列化和反序列化

1. 序列化
User user = new User("hyf",22,true);   //假設(shè)有一個(gè)userBean里面有name,age,gender
Gson gson = new Gson();
String json = gson.toJson(user);
//out: {"name":"hyf","age":22,"gender":true}
2. 反序列化
User user = gson.fromJson(json,User.class);
//此處的json為上面序列化輸出的json字符串

屬性重命名

修改User類幌甘,為name聲明SerializedName龄章。其中value設(shè)置屬性名,而alternate則設(shè)置多個(gè)備選屬性名

public class User{
    @SerializedName(value = "userName",alternate={"user_name","Name"})
    private String name;
    private int age;
    private boolean gender;
}

字段過(guò)濾

1. 基于@Expose注解

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

@Expose(serialize=true,deserialize=true)//序列化和反序列化都生效
  @Expose(serialize=false,deserialize=false)
//序列化和反序列化都不生效
   @Expose(serialize=true,deserialize=false)
//序列化生效碰镜,反序列化不生效
   @Expose(serialize=false,deserialize=true)
//序列化不生效,反序列化生效
2. 基于版本

Gson提供了@Since@Until兩個(gè)注解基于版本對(duì)字段進(jìn)行過(guò)濾习瑰,它們都包含一個(gè)Double值绪颖,用于設(shè)置版本號(hào)。

  • @Since 從...開(kāi)始
  • @Until 到...為止
  • 它們要配合GsonBuilder配合使用
    當(dāng)版本(GsonBuilder設(shè)置的版本)大于或等于Since值或小于Until時(shí)甜奄,字段會(huì)進(jìn)行序列化和反序列操作柠横,而沒(méi)有聲明注解的字段都會(huì)加入序列化和反序列操作窃款。

例子:修改User類

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 + '\'' +
            '}';
}
}

    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());

結(jié)果輸出:只會(huì)序列化和反序列化a,b,c

序列化:{"a":"A","b":"B","e":"E"}
反序列化:User{a='A',b='B',c='null',d='null',e='E'}
3.基于訪問(wèn)修飾符

通過(guò)GsonBuilder對(duì)象的excludeFieldsWithModifiers方法來(lái)指定不進(jìn)行序列化和反序列話操作的訪問(wèn)修飾符字段

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));
    }

輸出:private和static的字段將不會(huì)被序列化和反序列化

4.基于策略

通過(guò)GsonBuildersetExclusionStrategies(ExclusionStrategy... strategies)來(lái)直接排除指定字段名或者指定字段類型不進(jìn)行序列化和反序列化

Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy(){
 @Override
 public boolean shouldSkipField(FieldAttributes fieldAttributes) {
   //排除指定字段名(這里指定字段名為)
 return fieldAttributes.getName().equals("intField");
 }

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

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

addSerializationExclusionStrategy(ExclusionStrategy strategy);

  • addDeserializationExclusionStrategy(ExclusionStrategy strategy);

個(gè)性化設(shè)置

1. 序列化時(shí)輸出null
Gson gson = new GsonBuilder()
             .serializeNulls();
             .create();

序列化User類: 假設(shè)user類(null,24,true)
輸出:{"name":null,"age":24,"gender":true}

2.格式化輸出Json

Gson默認(rèn)序列化的json字符串不夠直觀晨继,可以使用GsonBuildersetPrettyPrinting進(jìn)行格式化輸出

Gson gson = new GsonBuilder()
            .serializeNulls()
            .setPrettyPrinting()
            .create();

輸出:

{
    "name":null,
    "age":24,
    "gender":true
}
3.格式化時(shí)間
Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
            .create();

TypeAdapter

TypeAdapter是一個(gè)泛型抽象類,用于接管某種類型的序列化和反序列過(guò)程搬俊,包含兩個(gè)抽象方法紊扬,分別用于自定義序列化和反序列化的過(guò)程。

例子:對(duì)應(yīng)還是使用User類(包含name,age,gender)
定義一個(gè)類繼承TypeAdapter

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

    @Override
    public User read(JsonReader jsonReader) throws IOException {
        User user = new User();
        //流式反序列化開(kāi)始
        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 "gender":
                    user.setGender(jsonReader.nextBoolean());
                    break;
            }

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

使用:

    Gson gson = new GsonBuilder()
                .registerTypeAdapter(User.class,new UserTypeAdapter())
                .create();
User user = new User("hyf",22,true);
String json = gson.toJson(user);
user = gson.fromJson(json,User.class);

輸出序列化后的json和反序列化后的user

{"Name":"hyf","Age":22,"Gender":true}
User{name="hyf",age=22,gender=true}

TypeAdapter同時(shí)接管了序列化和反序列化操作

  • JsonSerializer 只接管序列化過(guò)程的接口
  • JsonDeserializer 只接管反序列化過(guò)程的接口

TypeAdapterFactory

TypeAdapterFactory 是用于創(chuàng)建 TypeAdapter 的工廠類唉擂,通過(guò)參數(shù) TypeToken 來(lái)查找確定對(duì)應(yīng)的 TypeAdapter , 如果沒(méi)有就返回 null 并由 Gson 默認(rèn)的處理方法來(lái)進(jìn)行序列化和反序列化餐屎,否則就由客戶預(yù)定義的 TypeAdapter 來(lái)進(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 對(duì)象
            if (typeToken.getType().getTypeName().equals(User.class.getTypeName())) {
                return (TypeAdapter<T>) new UserTypeAdapter();
            }
            //找不到則返回null
            return null;
        }
    })
    .create();

原文地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腹缩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卵凑,更是在濱河造成了極大的恐慌庆聘,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺卢,死亡現(xiàn)場(chǎng)離奇詭異伙判,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)黑忱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門宴抚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人甫煞,你說(shuō)我怎么就攤上這事菇曲。” “怎么了抚吠?”我有些...
    開(kāi)封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵常潮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我楷力,道長(zhǎng)喊式,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任萧朝,我火速辦了婚禮岔留,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘检柬。我一直安慰自己献联,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著里逆,像睡著了一般进胯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上运悲,一...
    開(kāi)封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天龄减,我揣著相機(jī)與錄音,去河邊找鬼班眯。 笑死希停,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的署隘。 我是一名探鬼主播宠能,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼磁餐!你這毒婦竟也來(lái)了违崇?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诊霹,失蹤者是張志新(化名)和其女友劉穎羞延,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體脾还,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伴箩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鄙漏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗤谚。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怔蚌,靈堂內(nèi)的尸體忽然破棺而出巩步,到底是詐尸還是另有隱情,我是刑警寧澤桦踊,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布椅野,位于F島的核電站,受9級(jí)特大地震影響籍胯,放射性物質(zhì)發(fā)生泄漏鳄橘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一芒炼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧术徊,春花似錦本刽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暗挑。三九已至,卻和暖如春斜友,著一層夾襖步出監(jiān)牢的瞬間炸裆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工鲜屏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烹看,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓洛史,卻偏偏與公主長(zhǎng)得像惯殊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子也殖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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