Android中详尽的Gson(可能有你没用过的方式)

Gson使用

项目地址:https://github.com/google/gson

实例化Gson对象

  1. 通过构造函数获取

    Gson gson = new Gson();

  2. 通过GsonBuilder获取,可以进行多项配置

    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和数组/List转换

1. json转字符串数组
Gson gson = new Gson();
String jsonArray = "[\"3\",\"4\",\"5\"]";
String[] strings = gson.fromJson(jsonArray,String[].class);
2. 字符串数组转json
String jsonArray = gson.toJson(jsonArray,new TypeToken<String>(){}.getType());
3. json转List
String jsonArray = "[....]"  //此处jsonArray与(1)中相同
List<String> stringList = gson.fromJson(jsonArray,new TypeToken<List<String>>(){}.getType());
4. List转Json
String jsonArray = gson.toJson(stringList,new TypeToken<List<String>>(){}.getType());

序列化和反序列化

1. 序列化
User user = new User("hyf",22,true);   //假设有一个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设置属性名,而alternate则设置多个备选属性名

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

字段过滤

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两个注解基于版本对字段进行过滤,它们都包含一个Double值,用于设置版本号。

  • @Since 从...开始
  • @Until 到...为止
  • 它们要配合GsonBuilder配合使用
    当版本(GsonBuilder设置的版本)大于或等于Since值或小于Until时,字段会进行序列化和反序列操作,而没有声明注解的字段都会加入序列化和反序列操作。

例子:修改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());

结果输出:只会序列化和反序列化a,b,c

序列化:{"a":"A","b":"B","e":"E"}
反序列化:User{a='A',b='B',c='null',d='null',e='E'}
3.基于访问修饰符

通过GsonBuilder对象的excludeFieldsWithModifiers方法来指定不进行序列化和反序列话操作的访问修饰符字段

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的字段将不会被序列化和反序列化

4.基于策略

通过GsonBuildersetExclusionStrategies(ExclusionStrategy... strategies)来直接排除指定字段名或者指定字段类型不进行序列化和反序列化

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 方法在序列化和反序列化时都会生效,如果只是想指定其中一种情况下的排除策略或分别指定排除策略,可以改为使用以下两个方法

addSerializationExclusionStrategy(ExclusionStrategy strategy);

  • addDeserializationExclusionStrategy(ExclusionStrategy strategy);

个性化设置

1. 序列化时输出null
Gson gson = new GsonBuilder()
             .serializeNulls();
             .create();

序列化User类: 假设user类(null,24,true)
输出:{"name":null,"age":24,"gender":true}

2.格式化输出Json

Gson默认序列化的json字符串不够直观,可以使用GsonBuildersetPrettyPrinting进行格式化输出

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

输出:

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

TypeAdapter

TypeAdapter是一个泛型抽象类,用于接管某种类型的序列化和反序列过程,包含两个抽象方法,分别用于自定义序列化和反序列化的过程。

例子:对应还是使用User类(包含name,age,gender)
定义一个类继承TypeAdapter

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("Gender").value(user.isSex());
        //流式序列化结束
        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 "gender":
                    user.setGender(jsonReader.nextBoolean());
                    break;
            }

        }
        //流式反序列化结束
        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同时接管了序列化和反序列化操作

  • JsonSerializer 只接管序列化过程的接口
  • JsonDeserializer 只接管反序列化过程的接口

TypeAdapterFactory

TypeAdapterFactory 是用于创建 TypeAdapter 的工厂类,通过参数 TypeToken 来查找确定对应的 TypeAdapter , 如果没有就返回 null 并由 Gson 默认的处理方法来进行序列化和反序列化,否则就由客户预定义的 TypeAdapter 来进行处理。

Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new TypeAdapterFactory() {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
            //如果 Gson 需要与 User 类相关的 TypeAdapter ,则返回我们自己定义的 TypeAdapter 对象
            if (typeToken.getType().getTypeName().equals(User.class.getTypeName())) {
                return (TypeAdapter<T>) new UserTypeAdapter();
            }
            //找不到则返回null
            return null;
        }
    })
    .create();

原文地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容