Gson詳解:Java對象與JSON相互轉換的利器

1. Gson是什麼(What is Gson)

Gson是一個開源的Java庫,用於任意Java對象與JSON之間的相互轉換,由Google開發維護。java

Gson的優點:git

  • 簡單易用:以toJsonfromJson兩個方法爲核心
  • 不須要annotations的支持,能夠在缺乏源代碼或不方便修改源代碼的狀況下使用
  • 支持泛型和集合

github: https://github.com/google/gson
API Spec: http://google.github.io/gson/apidocs/github

2. 將Gson引入項目

  • 在Maven中加入依賴
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.5</version>
</dependency>
  • 將jar直接加入項目的lib文件夾

爲了圖省事,我把相應jar放在個人百度雲。(實際上是把maven下載的版本打包而已)json

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)api

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中讀取。可傳入相應WriterReader改變數據的去處或來源。maven

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:ui

public class Account {
	private String id;
	private String email;	
	private Date dateOfRegister = new Date();
	/* setter/getter */
}

3.6 自定義輸出格式

經過修改GsonBuilder的屬性,自定義輸出的結果:this

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. 說明

以上內容均參考官方文檔,若有錯誤,還望指正。

相關文章
相關標籤/搜索