1. 程式人生 > >Android框架---Google官方Gson解析(上)

Android框架---Google官方Gson解析(上)

Gson(又稱Google Gson)是Google公司釋出的一個開放原始碼的Java庫,主要用途為序列化Java物件為JSON字串,或反序列化JSON字串成Java物件。 JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,易於人閱讀和編寫,同時也易於機器解析和生成,廣泛應用於各種資料的互動中,尤其是伺服器與客戶端的互動。

GitHub中的原始碼地址:https://github.com/google/gson

AS在專案的app目錄下的buile.gradle新增gson依賴:(如果需要jar包,文末可以下載)


Gson的例項化方式:

Gson gson = new Gson();
//可以通過GsonBuilder配置多種選項
gson = new GsonBuilder()
        .setLenient()// json寬鬆
        .enableComplexMapKeySerialization()//支援Map的key為複雜物件的形式
        .serializeNulls() //智慧null
        .setPrettyPrinting()// 調教格式
        .disableHtmlEscaping() //預設是GSON把HTML 轉義的
        .create();

接下來介紹Gson的集中基本用法:

1、物件和json字串的相互轉換(先準備一個Person類)

public class Person {
	private int per_id;
	private String name;
	private String sex;
	private int age;

	public Person(int per_id, String name, String sex, int age) {
		this.per_id = per_id;
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	
	//get、set和toString方法...
}

測試程式碼:
/**
 * Created by Layne_Yao on 2017-9-28 上午10:46:43.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class GsonTest {

	public static void main(String[] args) {
		Gson gson = new Gson();
		// 可以通過GsonBuilder配置多種選項
		gson = new GsonBuilder()
				.setLenient()// json寬鬆
				.enableComplexMapKeySerialization()// 支援Map的key為複雜物件的形式
				.serializeNulls() // 智慧null
				.setPrettyPrinting()// 調教格式
				.disableHtmlEscaping() // 預設是GSON把HTML 轉義的
				.create();

		Person person = new Person(10, "layne", "man", 18);
		// 物件轉換為json字串
		String str = gson.toJson(person);
		System.out.println("物件轉換為json字串:" + str);

		// json字串轉化為物件
		Person person1 = gson.fromJson(str, Person.class);
		System.out.println("json字串轉化為物件:" + person1.toString());

	}

}

執行結果:



2、集合和json字串之間的轉換:

/**
 * Created by Layne_Yao on 2017-9-28 上午11:03:21.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class CollectionTest {
	public static void main(String[] args) {
		Gson gson = new Gson();

		// 1.1、List字串集合轉換為字串
		ArrayList<String> str_list = new ArrayList<>();
		for (int i = 0; i < 5; i++) {
			str_list.add("這是字串" + i);
		}
		String json_str = gson.toJson(str_list);
		System.out.println("這是list字串集合轉化為json:" + json_str);
		
		// 1.2、這是json集合轉化為list字元集合
		Type type = new TypeToken<ArrayList<String>>() {
		}.getType();
		ArrayList<String> sList = gson.fromJson(json_str, type);
		System.out.println("這是json集合轉化為list字元集合:" + sList);
		System.out.println("==========================================");
		
		
		// 2.1、List物件集合轉換為字串
		List<Person> list = new ArrayList<>();
		for (int i = 0; i < 2; i++) {
			Person person = new Person(i, "layne", "man", 18);
			list.add(person);
		}
		String json_str1 = gson.toJson(list);
		System.out.println("這是list物件集合轉化為json:" + json_str1);
		
		// 2.1、這是json轉化為List物件集合
		Type type1 = new TypeToken<ArrayList<Person>>() {
		}.getType();
		ArrayList<String> sList1 = gson.fromJson(json_str1, type1);
		System.out.println("這是json轉化為List物件集合:" + sList1);
		System.out.println("==========================================");
		
		
		//3.1、這是map集合轉化為json
		Map<String, Object> map = new HashMap<>();
		map.put("per_id", 5);
		map.put("name", "layne");
		map.put("sex", "man");
		map.put("age", "18");
		
		String json_str2 = gson.toJson(map);
		System.out.println("這是map集合轉化為json:" + json_str2);
		
		//3.2、從json字串轉化為map集合
		Type type2 = new TypeToken<Map<String, Object>>() {
		}.getType();
		Map<String, Object> map1 = gson.fromJson(json_str2, type2);
		System.out.println("這是json轉化為map集合:" + map1);
		
	}
}

執行結果:

接下來介紹抽象基類JsonElement的繼承體系類:

JSONObject、JSONArray和Android自帶的差不多,參見上篇Android網路傳輸資料json解析的基本認識

JsonNull:實際上就是null的字串欄位

JsonPrimitive:這個其實挺有意思的,我們知道如果json轉換成字串會包含引號的轉義,但是通過JsonPrimative我們可以獲得為轉義的字串

/**
 * Created by Layne_Yao on 2017-9-28 下午1:52:31.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class JsonTest {

	public static void main(String[] args) {
		// JsonNull jsonNull = new JsonNull();// 構造方法過時,推薦INSTANCE

		JsonNull jsonNull = JsonNull.INSTANCE;
		System.out.println("JsonNull:" + jsonNull);

		
		Gson gson = new Gson();
		Person person = new Person(1, "layne", "man", 18);
		String json_str = gson.toJson(person);
		System.out.println("json字串:" + json_str);

		JsonPrimitive jsonPrimitive = new JsonPrimitive(json_str);
		System.out.println("JsonPrimitive字串:" + jsonPrimitive);// 多了轉義字元,以及頭尾的雙引號:"{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"age\":18}"
		System.out.println("JsonPrimitive字串:" + jsonPrimitive.getAsString());	
	}
}

執行結果:


Gson庫中的註解:有五種註解


首先著重的先說明重新命名註解:SerializedName

註解的作用:轉換key關鍵字,json轉換成物件是,json欄位的key預設必須和宣告類的欄位名稱一樣。但是如果伺服器返回的資料中key是關鍵字,這該怎麼辦?例如key是case、switch等,我們在宣告類的時候是不能用這些欄位的。或許你會讓服務端那邊改動,那服務端可能要改動非常的大,但是實際情況是不太願意去改的。而這時候重新命名註解就派上用場了。
還有就是如果服務端返回的json的key太冗餘、或是不直觀,這是就可以簡化一下,程式碼看起來比較的優雅。

替換關鍵字的key:

/**
 * Created by Layne_Yao on 2017-9-28 下午4:08:23.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class AnnotationTest {
	public class Person {
		private int per_id;
		private String name;
		private String sex;
		@SerializedName("case")
		private int case_num;

		public Person(int per_id, String name, String sex, int case_num) {
			super();
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.case_num = case_num;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", case_num=" + case_num + "]";
		}

	}

	public static void main(String[] args) {
		Gson gson = new Gson();
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"case\":18}";
		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("服務端傳送的情況:"+json_str);
		System.out.println("移動端轉換的情況:"+person);
	}

}

執行結果:


替換冗餘、難看的key:

/**
 * Created by Layne_Yao on 2017-9-28 下午4:16:44.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class AnnotationTest1 {
	public class Person {
		private int per_id;
		private String name;
		private String sex;
		@SerializedName("home_light_state")
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			super();
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person [per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}
	}

	public static void main(String[] args) {
		Gson gson = new Gson();
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"home_light_state\":true}";
		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("服務端傳送的情況:"+json_str);
		System.out.println("移動端轉換的情況:"+person);
	}

}

執行結果:


註解作用2:結合alternate 提供多種備用欄位key來解析,@SerializedName(value = "state", alternate = { "plus", "all" })
如果json中有plus就會解析成state,如果有all也會解析成state,當然state依舊不變的。
注意1:value中的值不能出現在alternate中;
注意2:alternate的備選欄位會後面的替換前面的。

例項程式碼:

/**
 * Created by Layne_Yao on 2017-9-28 下午5:05:44.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class AnnotationTest2 {
	public class Person {
		private int per_id;
		private String name;
		private String sex;
		@SerializedName(value = "state", alternate = { "plus", "all" })
		private String state;

		public Person(int per_id, String name, String sex, String state) {
			super();
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person [per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}
	}

	public static void main(String[] args) {
		Gson gson = new Gson();
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"all\":\"廣東廣州\"}";
		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("服務端傳送:"+json_str);
		System.out.println("轉換成:" + person);
		System.out.println("==========================");

		String json_str1 = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"plus\":\"廣東廣州\"}";
		Person person1 = gson.fromJson(json_str1, Person.class);
		System.out.println("服務端傳送:"+json_str1);
		System.out.println("轉換成:" + person1);
		System.out.println("==========================");
		
		//all在state之後,所以all會解析成state,值則是all的原先的值
		String json_str2 = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":\"state廣東廣州\",\"all\":\"all廣東廣州\"}";
		Person person2 = gson.fromJson(json_str2, Person.class);
		System.out.println("服務端傳送:"+json_str2);
		System.out.println("轉換成:" + person2);
		System.out.println("==========================");
		
		//state在最後,不用解析,解析後的值也是state原先的
		String json_str3 = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"plus\":\"plus廣東廣州\",\"state\":\"all廣東廣州\"}";
		Person person3 = gson.fromJson(json_str3, Person.class);
		System.out.println("服務端傳送:"+json_str3);
		System.out.println("轉換成:" + person3);
		System.out.println("==========================");
	}

}

執行結果:

過濾註解:Expose

原始碼:預設既可序列化又可反序列化

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Expose {
  
  public boolean serialize() default true;

  public boolean deserialize() default true;
}

可以排除不需要序列化的欄位,需要配合GsonBuilder使用
Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();

不新增@Expose註解的欄位將不會解析,分為以下幾種情況:

1、不新增@Expose註解等同於@Expose(deserialize = false,serialize = false) 不做任何解析
2、@Expose(deserialize = true,serialize = false) 只解析用用,也就是反序列化可以,序列化不可以
3、@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行
4、@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化

例項程式碼:不新增@Expose註解等同於@Expose(deserialize = false,serialize = false) 不做任何解析

/**
 * Created by Layne_Yao on 2017-9-29 上午9:29:08.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class ExposeTest {
	public static class Person {
		private int per_id;
		private String name;
		private String sex;
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}

	}

	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化:"+json_str1);
	}
}

執行結果:


@Expose(deserialize = true,serialize = false) 只解析用用,也就是反序列化可以,序列化不可以

/**
 * Created by Layne_Yao on 2017-9-29 上午9:59:04.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class ExposeTest3 {
	public static class Person {
		@Expose(deserialize = true,serialize = false)
		private int per_id;
		@Expose(deserialize = true,serialize = false)
		private String name;
		@Expose(deserialize = true,serialize = false)
		private String sex;
		@Expose(deserialize = true,serialize = false)
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}

	}
	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化:"+json_str1);
	}
}

執行結果:


@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行

/**
 * Created by Layne_Yao on 2017-9-29 上午9:56:57.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class ExposeTest2 {
	public static class Person {
		@Expose(deserialize = false,serialize = true)
		private int per_id;
		@Expose(deserialize = false,serialize = true)
		private String name;
		@Expose(deserialize = false,serialize = true)
		private String sex;
		@Expose(deserialize = false,serialize = true)
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}

	}
	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化:"+json_str1);
	}
}

執行結果:


@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化

/**
 * Created by Layne_Yao on 2017-9-29 上午9:53:38.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class ExposeTest1 {
	public static class Person {
		@Expose //等同於 @Expose(deserialize = true,serialize = true)
		private int per_id;
		@Expose
		private String name;
		@Expose
		private String sex;
		@Expose
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}

	}

	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化:"+json_str1);

	}

}

執行結果:


版本控制註解:Since、Util

Since註解:Gson例項配置GsonBuilder.setVersion(n)使用,當n>=v時,才會序列化解析

例項程式碼:

/**
 * Created by Layne_Yao on 2017-9-29 上午10:00:37.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class SinceTest {
	public static class Person {
		 @Since(2)
		private int per_id;
		 @Since(2)
		private String name;
		 @Since(2)
		private String sex;
		 @Since(2)
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}

	}
	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().setVersion(1)//版本為1
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化v=1:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化v=1:"+json_str1);
		System.out.println("=================================");
		
		Gson gson1 = new GsonBuilder().setVersion(2)//版本為2
				.create();
		Person person2 = gson1.fromJson(json_str, Person.class);
		System.out.println("反序列化v=2:" + person2);

		Person person3 = new Person(2, "layne", "man", true);
		String json_str2 = gson1.toJson(person3);
		System.out.println("序列化v=2:"+json_str2);
		System.out.println("=================================");
		
		Gson gson2 = new GsonBuilder().setVersion(3)//版本為3
				.create();
		Person person4 = gson2.fromJson(json_str, Person.class);
		System.out.println("反序列化v=3:" + person4);

		Person person5 = new Person(2, "layne", "man", true);
		String json_str3 = gson2.toJson(person5);
		System.out.println("序列化v=3:"+json_str3);
	}

}

執行結果:


Util註解:Gson例項配置GsonBuilder.setVersion(n)使用,當n<v時,才會序列化解析

例項程式碼:

/**
 * Created by Layne_Yao on 2017-9-29 上午10:17:54.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class UtilTest {
	public static class Person {
		@Until(2)
		private int per_id;
		@Until(2)
		private String name;
		@Until(2)
		private String sex;
		@Until(2)
		private boolean state;

		public Person(int per_id, String name, String sex, boolean state) {
			this.per_id = per_id;
			this.name = name;
			this.sex = sex;
			this.state = state;
		}

		@Override
		public String toString() {
			return "Person-->[per_id=" + per_id + ", name=" + name + ", sex="
					+ sex + ", state=" + state + "]";
		}
	}

	public static void main(String[] args) {
		String json_str = "{\"per_id\":1,\"name\":\"layne\",\"sex\":\"man\",\"state\":true}";
		Gson gson = new GsonBuilder().setVersion(1)// 版本為1
				.create();

		Person person = gson.fromJson(json_str, Person.class);
		System.out.println("反序列化v=1:" + person);

		Person person1 = new Person(2, "layne", "man", true);
		String json_str1 = gson.toJson(person1);
		System.out.println("序列化v=1:" + json_str1);
		System.out.println("=================================");

		Gson gson1 = new GsonBuilder().setVersion(2)// 版本為2
				.create();
		Person person2 = gson1.fromJson(json_str, Person.class);
		System.out.println("反序列化v=2:" + person2);

		Person person3 = new Person(2, "layne", "man", true);
		String json_str2 = gson1.toJson(person3);
		System.out.println("序列化v=2:" + json_str2);
		System.out.println("=================================");

		Gson gson2 = new GsonBuilder().setVersion(3)// 版本為3
				.create();
		Person person4 = gson2.fromJson(json_str, Person.class);
		System.out.println("反序列化v=3:" + person4);

		Person person5 = new Person(2, "layne", "man", true);
		String json_str3 = gson2.toJson(person5);
		System.out.println("序列化v=3:" + json_str3);

	}

}

執行結果: