Gson 的深入使用

《Gson 的深入使用》

在实习的这段期间,入手了第一个开发的项目,本来是挺开心的,但是一调接口看返回的json数据我就头疼,心里无数次的吐槽后台开发。

如果你看过这四篇文字,那么恭喜你,你已经练就了葵花宝典,啊不是(呸),是九阳神功啊!

(一)Gson的基本用法

  • 基础用法toJson

    toJson()方法将对象转换成Json字符串

    List<String> strings = new ArrayList<>();strings.add("至尊宝");strings.add("紫霞");strings.add("还有我");Gson gson = new Gson();String src = gson.toJson(strings);System.out.println("src :" + src);

    结果 : src :[“至尊宝”,”紫霞”,”还有我”]

    User user = new User("至尊宝", 1000, new User.Course("紫霞", 2000));Gson gson = new Gson();String src = gson.toJson(user);System.out.println("src :" + src);

    结果 :src :{“name”:”至尊宝”,”age”:1000,”course”:{“chinese”:”紫霞”,”address”:2000}}

  • 基础用法fromJson

    Gson提供了fromJson()方法来实现从Json字符串转化为到java实体的方法。

    比如json字符串为:[{“name”:”name0”,”age”:0}]

     String json = "{\n" + " \"name\": \"至尊宝\",\n" + " \"age\": 1000,\n" + " \"course\": {\n" + " \"name\": \"紫霞\",\n" + " \"age\": 2000\n" + " }\n" + "}";Gson gson = new Gson();User user = gson.fromJson(json, User.class);System.out.println("user.getName() :" + user.getName());System.out.println("user.getCourse().getName() :" + user.getCourse().getName());

    结果 : user.getName() :至尊宝 ​ user.getCourse().getName() :紫霞

    (二)深入了解(@SerializedName )

  • 属性重命名 @SerializedName 注解的使用

返回来的json 数据总有不和谐的因素 so 所以就需要他了

{"name":"紫霞","age":1000,"emailAddress":"zixia@example.com"}{"name":"至尊宝","age":2000,"email_address":"zhizunbao@example.com"}

这个时候就需要添加注解进入里面

@SerializedName("email_address")public String emailAddress;

你以后你这样就能获得紫霞仙子么 ,哼!!!

《Gson 的深入使用》

当你看到这样情况的时候是不是懵逼了,谁看谁都蒙!!!

{"name":"紫霞","age":1000,"emailAddress":"zixia@example.com"}{"name":"至尊宝","age":2000,"email_address":"zhizunbao@example.com"}{"name":"牛魔王","age":10000,"email":"cow@example.com"}

当上面的三个属性(email_address、email、emailAddress)都中出现任意一个时均可以得到正确的结果。

@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})public String emailAddress;

(三)Gson中使用泛型

当使用了Gson之后我发现我每次看接口回调的数据之后我都是二话不说,转化为实体类,但是如果数据的类型的时候呢?

比如下面这种情况,就需要使用TypeToken

["紫霞","至尊宝","牛魔王"]
Gson gson = new Gson();String jsonArray = "[\"紫霞\",\"至尊宝\",\"牛魔王\"]";String[] strings = gson.fromJson(jsonArray, String[].class);

当然Gson为我们提供了TypeToken来实现对泛型的支持,所以当我们希望使用将以上的数据解析为List时需要这样写。

但是当我们解析这个json的时候一般用数据、List,当让list增删都是比较方便的,项目实际中用的的比较多

Gson gson = new Gson();String jsonArray = "[\"紫霞\",\"至尊宝\",\"牛魔王\"]";String[] strings = gson.fromJson(jsonArray, String[].class);List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

当然上述的情况是理想的情况,要是实际的情况呢???

引入泛型可以减少无关的代码,正常情况下

{"code":"0","message":"success","data":{}}{"code":"0","message":"success","data":[]}

​ 但是我们真正需要的data所包含的数据,而code只使用一次,message则几乎不用。如果Gson不支持泛型或不知道Gson 支持泛型的同学一定会这么定义.

public class UserResponse { public int code; public String message; public User data;}

但是接口的数据变了(纳尼,竟然变了) User 类 变化为List 了,你就说你蒙不蒙吧。

​ 这个时候很明显code,和message被重复定义了多次,通过泛型的话我们可以将codemessage字段抽取到一个Result的类中,这样我们只需要编写data字段,如:

public class Result<T> { public int code; public String message; public T data;}

哎 。。。。 看到这里 我就蒙了 你别蒙就行 下面下这段代码,你就会感觉春梦(呸)春风铺面

这段因为的是怪盗kidou 中的代码,大家可以去试试!!!

没有引入泛型之前时写法

public class UserResult { public int code; public String message; public User data;}//=========public class UserListResult { public int code; public String message; public List<User> data;}//=========String json = "{..........}";Gson gson = new Gson();UserResult userResult = gson.fromJson(json,UserResult.class);User user = userResult.data;UserListResult userListResult = gson.fromJson(json,UserListResult.class);List<User> users = userListResult.data;

上面有两个类UserResultUserListResult,有两个字段重复,几个还行 ,我还能承受,要是几十个我就要大宝剑

(再呸)吐血了。

/不再重复定义Result类Type userType = new TypeToken<Result<User>>(){}.getType();Result<User> userResult = gson.fromJson(json,userType);User user = userResult.data;Type userListType = new TypeToken<Result<List<User>>>(){}.getType();Result<List<User>> userListResult = gson.fromJson(json,userListType);List<User> users = userListResult.data;

看出区别了么?只要多一行代码 就有不一样!!!

(四)字段过滤的几种形式

1. 基于@Expose注解

《Gson 的深入使用》

使用方法:简单说来就是需要导出的字段上加上@Expose 注解,不导出的字段不加,注意是不导出的不加,注意是不导出的不加,注意是不导出的不加(重要的事情说三遍)。

​ @Expose 注解直译过来的意思就是暴露,对应所处的暴露的极端。这里就又要提了,以前我们用Gson序列化和反序列化的时候不是也没有用@Expose么,怎么也能处理这个时候就该注解必须和GsonBuilder配合使用。才能正常的使用。

public class Result<T> { @Expose(deserialize = true, serialize = false)//反序列的时候生效,反之序列化的时候生效 public String name; @Expose(deserialize = true,serialize = true)//序列化和反序列化都都生效 public int id; @Expose(deserialize = false,serialize = false) // 和不写是一样的 不需要序列化,所以不加 @Expose 注解,也是一样的 public T course;}

当然在使用Gson的时候也不能只是简单的new 了。

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

之后使用gson的时候就可以排除你想要排除的字段了。

2.基于访问修饰符

对于修饰符大家可能并不陌生, publicstaticfinalprivateprotected,当然Gson对修饰符也做了相关的处理。

public class Course { final String id = "id"; static String age = "age"; private String classId = "classId"; public String chinese = "chinese"; protected String math = "math"; String mathId = "mathId"; int chineseId = 10;}

请原谅我蹩脚的英语!!!

这里面我分别给Course类设置了不同的字段。

// final String id = "id";// static String age = "age";// private String classId = "classId";// public String chinese = "chinese";// protected String math = "math";// String mathId = "mathId";// int chineseId = 10;Course course = new Course();Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC,Modifier.PRIVATE).create(); System.out.println(gson.toJson(course));

使用GsonBuilder.excludeFieldsWithModifiers构建gson,支持int形的可变参数。

这里面我分别对finalstaticprivate,类型做出了排除

输入结果如下:

{“chinese”:”chinese”,”math”:”math”,”mathId”:”mathId”,”chineseId”:10}

3.基于策略(自定义规则)

​ 基于策略来说 可以这么讲完全是自定义的,可以灵活的使用,但是在项目实战中,用@Expose还是比较多的,但是不好的就是代码量比较大。

​ 基于策略是利用Gson提供的ExclusionStrategy接口,同样需要使用GsonBuilder,相关API分别是addSerializationExclusionStrategyaddDeserializationExclusionStrategy分别针对序列化和反序化时。

/** * 自定义删除的类或者是字段 * @param ExclusionField 删除的字段 * @param ExclusionClazz 删除的类 * @return Gson */ public static Gson ExclusionGsonField(String ExclusionField, Class<?> ExclusionClazz) { return new GsonBuilder().addDeserializationExclusionStrategy(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { // 这里作判断,决定要不要排除该字段,return true为排除 if (ExclusionField.equals(f.getName())) return true; //按字段名排除 //Expose expose = f.getAnnotation(Expose.class); //if (expose != null && expose.deserialize() == true) //return true; //按注解排除 return false; } @Override public boolean shouldSkipClass(Class<?> clazz) { // 直接排除某个类 ,return true为排除 return (clazz == ExclusionClazz); // return (clazz == clazz || clazz == Long.class); } }).create(); }

这里我对其进行了封装,使用的是反序列化,也可是使用的是序列化大家可以看下这里。

这里我简单说明下,删除的字段一定要和实体类或者是json的字段是一样的,删除类的情况下 没有可以设置为null。

大家一定有以为我为什么吧按注解排除的给注释掉了,这个因人而异,有的项目中可能会需要,需要的时候去掉修改下就可以

是不是感觉到了Gson的强大之处。

欢迎大家进群交流,QQ群:471395156

坐在公主旁的猴子

    原文作者:Android
    原文地址: https://juejin.im/entry/586b5fafac502e12d62b7535
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞