1. Gson是什么(What is Gson)
Gson是一个开源的Java库,用于任意Java对象与JSON之间的相互转换,由Google开发维护。
Gson的优势:
- 简单易用:以
toJson
和fromJson
两个方法为核心 - 不需要annotations的支持,可以在缺少源代码或不方便修改源代码的情况下使用
- 支持泛型和集合
github: https://github.com/google/gson
API Spec: http://google.github.io/gson/apidocs/
2. 将Gson引入项目
- 在Maven中加入依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.5</version>
</dependency>
- 将jar直接加入项目的lib文件夹
为了图省事,我把相应jar放在我的百度云。(其实是把maven下载的版本打包而已)
3. 示例(How to use)
3.1 --自定义测试类--
public class Person implements Serializable, Comparable<Person>{
private static final long serialVersionUID = 2373954257153196535L;
private String name;
private int age;
private String gender;
//实现Comparable只是为了测试Set的序列化/反序列化,并无其他意思
public int compareTo(Person o) {
if(o == null) return -1;
if(this == o) return 0;
if(this.getName().equals(o.getName()) && this.getAge() == o.getAge() && this.getGender() == o.getGender()) return 0;
return -1;
}
// a series of setter/getter
}
3.2 序列化
Java对象 → JSON:toJson(Object)
Person p1 = new Person("David", 26, "male");
Person p2 = new Person("Annie", 23, "female");
Person p3 = new Person("琼恩", 29, "男");
Gson gson = new Gson();//也可以通过new GsonBuilder().create();来实例化
//单个对象
String json = gson.toJson(p1);//{"name":"David","age":26,"gender":"male"}
//List
List<Person> list = Arrays.asList(p1, p2, p3);
String jsonList = gson.toJson(list);
//Set
Set<Person> set = new HashSet<Person>();
set.add(p1);
set.add(p2);
set.add(p1);
String jsonSet = gson.toJson(set);
//数组:先转换成List
Person[] arr = {p1, p2, p3};
List<Person> jsonArrList = Arrays.asList(arr);
String jsonArr = gson.toJson(jsonArrList);
/*
* 关于Java关键字:transient
*
* transient声明的field(成员变量)在对象序列化时会被忽略,
* 常用于声明password之类比较敏感的变量。
* transient不能用于声明方法。(反正方法既不会也没必要被序列化)
*
* 由于gson.toJson(obj)涉及序列化,transient在此也会生效,
* 即transient声明的变量不会出现在生成的json(String)中。(亲测)
*/
3.3 反序列化
JSON → Java对象:fromJson(String, Type)
- 反序列化时,必须提供反序列化的类型
java.lang.reflect.Type
- 对于普通的引用类型(Object子类),可使用
java.lang.Class
对象(实现了Type接口)
Type t1 = Person.class;
Type t2 = p1.getClass();
boolean flag = (t1 == t2);//true
Person person = gson.fromJson(json, t1);
System.out.println(person.getName());//David
- 对于参数化类型(即泛型),可通过
com.google.gson.reflect.TypeToken
获取其类型
Type setType = new TypeToken<Set<Person>>(){}.getType();//TypeToken<T>的Constructor(构造器/构造方法)为protected, 使用匿名内部类的方式进行实例化
Set<Person> people = gson.fromJson(jsonSet, setType);
Iterator<Person> ps = people.iterator();
while(ps.hasNext()){
System.out.println(ps.next().getName());
}
3.4 重定向数据来源/输出
默认情况下,toJson(Object)
将生成的JSON数据保存在一个StringWriter
中;fromJson(String, Type)
则是从String中读取。可传入相应Writer
或Reader
改变数据的去处或来源。
File f = new File("/Users/Lawrence/Documents/out.txt");
Writer out = new FileWriter(f);
gson.toJson(set, out);//将生成的JSON数据保存在文件中,而不是默认的String
out.close();
Reader reader = new FileReader(f);
Set<Person> setFromFile = gson.fromJson(reader, setType);//从文件中读取数据,而不是默认的String
System.out.println(setFromFile.size());//2
reader.close();
/*
* 改变数据输出,需要java.lang.Appendable
* 事实上Writer就实现了Appendable,所以其子类都满足这个条件
*/
3.5 --修改自定义测试类--
Person类增加两个变量:
- geo:长度为2的double数组用于表示地理位置,即经纬度
- Account
public class Person implements Serializable, Comparable<Person>{
private static final long serialVersionUID = 2373954257153196535L;
private String name;
private int age;
private String gender;
private double[] geo = new double[2];
private Account account;
/* a series of setter/getter */
}
Account.java:
public class Account {
private String id;
private String email;
private Date dateOfRegister = new Date();
/* setter/getter */
}
3.6 自定义输出格式
通过修改GsonBuilder的属性,自定义输出的结果:
Person p1 = new Person("David", 26, "male");
Account ac = new Account("id", "<h1>test1@test1.com</h1>");
p1.setAccount(ac);
Person p2 = new Person("Rose", 23, "女");
Account ac2 = new Account("id2", "<p>test2@test2.com</p>");
p2.setAccount(ac2);
Person p3 = new Person();
p3.setName("Hello");
List<Person> list = Arrays.asList(p1, p2, p3);
Gson gson = new GsonBuilder()
.setPrettyPrinting()//自动换行和添加缩进
.serializeNulls()//保留null的变量并将值设为null
.disableHtmlEscaping()//不会对用于表示HTML标签的"<"和">"编码
.setDateFormat("yyyy-MM-dd")//为所有java.util.Date定义输出格式
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
//定义变量名的显示方式,如此处将Account的dateOfRegister定义输出为"Date Of Register"
.create();
System.out.println(gson.toJson(list));
以上输出为
[
{
"Name": "David",
"Age": 26,
"Gender": "male",
"Geo": [
0.0,
0.0
],
"Account": {
"Id": "id",
"Email": "<h1>test1@test1.com</h1>",
"Date Of Register": "2015-12-16"
}
},
{
"Name": "Rose",
"Age": 23,
"Gender": "女",
"Geo": [
0.0,
0.0
],
"Account": {
"Id": "id2",
"Email": "<p>test2@test2.com</p>",
"Date Of Register": "2015-12-16"
}
},
{
"Name": "Hello",
"Age": 0,
"Gender": null,
"Geo": [
0.0,
0.0
],
"Account": null
}
]
3.7 操作JSON树
将3.6中添加的由3个Person对象组成的list为例:
JsonElement root = gson.toJsonTree(list);//3个Person对象
if(root.isJsonArray()){
JsonArray arr = (JsonArray) root;
Iterator<JsonElement> iter = arr.iterator();
JsonElement target = null;
while(iter.hasNext()){
JsonObject element = (JsonObject) iter.next();
String name = element.get("Name").getAsString();
if("Hello".equals(name)){
// arr.remove(element);//不能调用ArrayList的remove(), 因为会抛出java.util.ConcurrentModificationException
iter.remove();//需要调用的是Iterator的remove();
}
}
}
System.out.println(gson.toJson(root));
4. 说明
以上内容均参考官方文档,如有错误,还望指正。
- github: https://github.com/google/gson
- API Spec: http://google.github.io/gson/apidocs/