简介
Gson是Google发布的一个开源Java类库,能够很方便的在Java对象和JSON字符串之间进行序列化和反序列化。目前主流进行JSON解析的开源库主要有Fastjson、Jackson、Gson等,各有优劣,关于它们的对比分析见我在知乎上的这个回答:java中处理JSON的开源工具都有些什么?那个比较好用?在这篇文章中主要介绍一下Gson的进阶用法。
基本用法
Gson的基本用法非常简单,假如你有这样一个JSON文件:
{
"name": "username",
"age": 20,
"admin": true
}
你只需要定义这样一个Java类:
public class User {
private String name;
private int age;
private boolean admin;
// IDE自动生成的Getter和Setter
}
然后,序列化和反序列化都只需要一句话就能搞定:
// 序列化
String string = new Gson().toJson(user);
// 反序列化
User user = new Gson().fromeJson(string, User.class);
泛型的反序列化
如果整个JSON字符串不是一个JSONObject而是JSONArray,使用上面的语句尝试反序列化时就会报错,使用类似List.class的代码无法通过编译,事实上这和Java泛型的实现机制有关系,Java的泛型对象的类型不能直接通过类型本身获取到。
在这里,Gson提供了TypeToken来实现得到泛型的实际类型,例如:
// 序列化
String string = new Gson().toJson(userList);
// 反序列化
List<User> userList = new Gson().fromeJson(string, new TypeToken<List<User>>(){}.getType());
这个TypeToken的实现过程非常精彩,对于理解Java的泛型实现有非常大的帮助,有兴趣的同学可以阅读一下TypeToken的源码。
变量名的对应
通常使用JSON的场景是从服务器端获取数据,如果服务器编写接口的人编码风格与你不一致,直接使用Gson转换而来的对象的成员变量和方法会显得非常丑陋。例如如果接口使用下划线风格命名一个变量last_login_time
,那么你在调用这个变量的方法就成了user.getLast_login_time()
,这是强迫症所不能忍的。
幸好Google提供了非常方便的注解功能供接口变量和Java成员变量之间的映射,你只需要这么写:
public class User {
private String name;
private int age;
private boolean admin;
@SerializedName("last_login_time")
private String lastLoginTime;
// IDE自动生成的Getter和Setter
}
这样Gson就能自动将JSON中的last_login_time
映射为Java类中的lastLoginTime
变量了,在get和set的时候也是漂亮的驼峰命名法了:user.getLastLoginTime()
。
ps: 这个技巧在接口编写者英语不好的时候特别有用(逃
控制变量是否序列化
在实际使用过程中,会有各种情况导致我们的Java类与和接口JSON变量不同。比如说在本地我们需要在User类中定义一个loginTimes
变量来记录登录的次数,这个变量是接口中没有的,我们序列化User传给服务器时也不希望有这个变量,如何处理这种情况呢?
Gson提供了@Expose
注解来进行控制成员变量的序列化和非序列化,这个注解有两个变量:serialize
和deserialize
,默认都是true
。需要注意的是若要使这个注解生效,必须使用GsonBuilder.excludeFieldsWithoutExposeAnnotation()
方法来构建Gson对象。
如果我们在对象中使用如下注解:
public class User {
@Expose
private String name;
@Expose(serialize = false)
private int age;
@Expose(serialize = false, deserialize = false)
private boolean admin;
// IDE自动生成的Getter和Setter
}
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
那么在反序列化时只会给name
和age
字段赋值,而序列化时只输出name
字段。
与@Expose
注解类似,Gson还提供了@Since
注解来进行版本控制,使用GsonBuilder构建时指定版本后高于该版本的字段在序列化和反序列化时都将被忽略:
public class User {
@Since(1.0)
private String name;
@Since(1.1)
private int age;
@Since(1.1)
private boolean admin;
// IDE自动生成的Getter和Setter
}
Gson gson = new GsonBuilder().setVersion(1.0).create();
此时,age
和admin
字段由于版本号高于Gson对象指定的1.0版本,在转换过程中会被自动忽略,也可以达到控制变量是否序列化的目的。
本文首发http://www.dss886.com,转载请注明