GSON详解
GSON
GSON彌補了JSON的許多不足的地方,在實際應用中更加適用于Java開發。在這里,我們主要講解的是利用GSON來操作java對象和json數據之間的相互轉換,包括了常見的對象序列化和反序列化的知識。
一、前言
因為json有2種類型:
- 一種是對象,object -> {key:value,key:value,…} 。
- 另一種是數組,array -> [value,value,…] 。
所以針對這兩種類型,來展開對json數據的操作。
GSON在解析json的時候,大體上有2種類型,一種是直接在內存中生成object或array,通過手工指定key來獲取值;另一種是借助javabean來進行映射獲取值。
二、對 json 數據進行反序列化,得到java 對象
1、不借助java 類,直接解析json 數據
1.1、json 是對象類型
當ajax傳過來的json數據屬于對象時,不論這個對象簡單還是復雜,都可以輕松地把它們給解析出來。
ajax傳過來的json數據(是對象形式):
var data_json = {"sex": '男',"hobby":["baskte","tennis"],"introduce": {"name":"tom","age":23}};data: JSON.stringify(data_json),GSON解析:
BufferedReader reader = request.getReader();// 讀取json數據StringBuffer buffer = new StringBuffer();String s;while ((s = reader.readLine()) != null) {buffer.append(s);}String json = buffer.toString();System.out.println("json:" + json); // json解析器,解析json數據JsonParser parser = new JsonParser();JsonElement element = parser.parse(json);// json屬于對象類型時if (element.isJsonObject()) { JsonObject object = element.getAsJsonObject(); // 轉化為對象// 1. value為string時,取出stringString sex = object.get("sex").getAsString(); System.out.println("sex:" + sex);// 2. value為array時,取出arrayJsonArray hobbies = object.getAsJsonArray("hobby"); // for (int i = 0; i < hobbies.size(); i++) {String hobby = hobbies.get(i).getAsString();System.out.println("hobby:" + hobby);}// 3. value為object時,取出objectJsonObject introduce = object.getAsJsonObject("introduce");String name = introduce.get("name").getAsString();int age = introduce.get("age").getAsInt();System.out.println("name:" + name+";age:" + age);}解讀:
很明顯,對于傳過來的對象類型的json數據,使用GSON是很方便進行解析的,在得到了json數據對應的JsonObject 對象之后,我們就可以很簡單地進行操作了。這種方法是直接獲取json中的值,而沒有進行java對象的還原(簡單情況下,沒有必要生成相應的javabean)。
1.2、json 是數組類型
ajax傳過來的json數據(是數組形式):
var data_json = ["cake",2,{"brother":"tom","sister":"lucy"},["red","orange"] ];data: JSON.stringify(data_json),GSON解析:
BufferedReader reader = request.getReader();StringBuffer buffer = new StringBuffer();String s;while ((s = reader.readLine()) != null) {buffer.append(s);}String json = buffer.toString();System.out.println("json:"+json);// json解析器,解析json數據JsonParser parser = new JsonParser();JsonElement element = parser.parse(json);// json屬于數組類型if (element.isJsonArray()) { JsonArray array = element.getAsJsonArray();// 1. value為string時,取出stringString array_1 = array.get(0).getAsString();System.out.println("array_1:"+array_1);// 2. value為int時,取出intint array_2 = array.get(1).getAsInt();System.out.println("array_2:"+array_2);// 3. value為object時,取出objectJsonObject array_3 = array.get(2).getAsJsonObject();String brother = array_3.get("brother").getAsString();String sister = array_3.get("sister").getAsString();System.out.println("brother:"+brother+";sister:"+sister);// 4. value為array時,取出arrayJsonArray array_4 = array.get(3).getAsJsonArray();for (int i = 0; i < array_4.size(); i++) {System.out.println(array_4.get(i).getAsString());}}解讀:
當json是數組類型的時候,使用GSON操作和上一小節幾乎差不多,只不過是第一步生成的json對象是數組而已。上面2種方式解析json十分簡單,在日常使用中足夠了。
但是對于有規律的json數據,比如往往是可以映射成一個javabean對象,那么我們就沒有必要一個個手工取值了,我們可以借助javabean配合GSON來更加快速地解析json數據。
2、借助java 類,生成對應java 對象來解析數據
詳細的前端json 數據,可以看前面的反例,以下只是使用直接的json數據進行說明。
生成對于的java對象之后,就可以通過getter方法來獲取相應的數據了。
通用代碼:
在這個方法里,借助json數據來生成java對象的代碼都是一致的:
Gson gson = new Gson(); BeanType bean = gson.fronJson(jsonData, BeanType.class);2.1、 json 是對象類型
2.1.1 基本案列
json 數據
{"name":"tom","salary":2999}java類
public class MyEntry {private String name;private int age;public String address;public int salary;// getter、setter、toString }java 代碼
String json1 = "{\"name\":\"tom\",\"salary\":2999}"; Gson gson1 = new Gson(); MyEntry entry1 = gson1.fromJson(json1, MyEntry.class); System.out.println(entry1.toString()); // name:tom,age:0,address:null,salary:2999解讀
可以看出,對于不完整的json 數據,在我們映射了相應的java 類之后,轉化得到的java對象,未賦值的字段都是默認值。這就符合java的規范和常理。
2.1.2 字段名并不一致怎么辦?
如果前端傳過來的json 數據的key和我們java類的字段不一致,就需要我們在java類中手工進行指定。
@SerializedName() 注解
比如對于上面的json 數據,salary 改成money ,我們得到的java對象中,salary 就會變成默認值:0。
因此,我們要使用注解:
@SerializedName("money") private String salary;@SerializedName({"money", "salary"}) // 可以有多個備選值 private String salary;2.1.3 如何限定某個字段不參加序列化或反序列化?
@Expose()注解
如果想要讓java類的某些字段不參加序列化或反序列化,可以顯示來設置。如:
@Expose(serialize=false,deserialize=false) private String name;上面的name 字段將不參加序列化及反序列化。
2.1.4 復合的對象怎么處理?
當json 數據是對象形式時,常見的value 會是一個數組或對象。如:
{"name": "tom","age": 0,"money": 2999,"hobbies": ["basket","tennis"],"collections": {"2": "paint","3": "mouse"} }舉一反三,value 是數組時(hobbies),對應在java類中也是數組;value 是對象時,對應在java類中就是map(k-v對)了。
因此,我們可以很容易得到對應的java類:
private List<String> hobbies; private Map<Integer, String> collections;解讀: 可知,再復雜的json 數據,我們也可以構造出對應的java類。
2.2. json 是數組類型
2.2.1 基本案例:
json數據
["apple", "banana", "pear"]顯然,數組在java中對應的也是數組。
java代碼
String json2 = "[\"apple\", \"pear\", \"banana\"]"; Gson gson2 = new Gson(); // 傳入的java類型是String[].class String[] fruits = gson2.fromJson(json2, String[].class);2.2.2 我想用List 數組
對于上面這種簡單的數組形式的json數據,我們還可以反序列化為List類型的數組。因為List進行增刪改都比較方便。
這里就要使用泛型了,具體的泛型講解,會在下面進行說明。
String json2 = "[\"apple\", \"pear\", \"banana\"]"; Gson gson2 = new Gson(); List<String> fruitList = gson2.fromJson(json2, new TypeToken<List<String>>(){}.getType());3、使用泛型
有的時候,傳過來的json數據在格式上是很相近的,只不過某個字段的value不固定,如果為此生成多個相似的java類就十分多余了。
如:前端傳過來的json數據主要是2類:
{"code":"0","message":"success","data":{}} {"code":"0","message":"success","data":[]}對于字段data ,有時候是對象,有時候是數組。
這里,我們將使用Result 來映射json數據,使用MyEntry 類來映射json 數據的data 部分。這意味著,對于不同的json數據,我們將不再生成多個java類,而是動態生成所需的java對象。
result對象
public class Result<T>{public int code;public String message;public T data;// getter、setter }3.1 data為對象的json1:
{"code": 0,"message": "success","data": [{"name": "tom","age": 32,"address": "street one","salary": 4999},{"name": "tom","age": 32,"address": "street one","salary": 4999}] }java代碼
String typeJson1 = "{\n" +" \"code\":0,\n" +" \"message\":\"success\",\n" +" \"data\":{\n" +" \"name\":\"tom\",\n" +" \"age\":32,\n" +" \"address\":\"street one\",\n" +" \"salary\":4999\n" +" }\n" +"}"; Gson typeGson1 = new Gson(); // 動態生成所需的java類的類型 Type type1 = new TypeToken<Result<MyEntry>>(){}.getType(); // 動態生成java對象 Result<MyEntry> result1 = typeGson1.fromJson(typeJson1, type1); System.out.println(result1);3.2 data為數值的json2:
{"code": 0,"message": "success","data": [{"name": "tom","age": 32,"address": "street one","salary": 4999},{"name": "lucy","age": 24,"address": "street three","salary": 2333}] }java代碼
String typeJson2 = "{\n" +" \"code\": 0,\n" +" \"message\": \"success\",\n" +" \"data\": [\n" +" {\n" +" \"name\": \"tom\",\n" +" \"age\": 32,\n" +" \"address\": \"street one\",\n" +" \"salary\": 4999\n" +" },\n" +" {\n" +" \"name\": \"lucy\",\n" +" \"age\": 24,\n" +" \"address\": \"street three\",\n" +" \"salary\": 2333\n" +" }\n" +" ]\n" +"}"; Gson typeGson2 = new Gson(); // 再次動態生成java類型 Type type2 = new TypeToken<Result<List<MyEntry>>>(){}.getType(); // 再次動態生成java對象 Result<List<MyEntry>> result2 = typeGson2.fromJson(typeJson2, type2); System.out.println(result2);四、java 對象序列化為json 數據
這一部分,主要是講解如何將一個java對象序列化為json數據,也會涉及到如何組裝這個java對象。
4.1、由具體的java類對象,序列化為json 數據
我們可以直接把java對象給序列化為json數據。對于未設置的屬性,會采取默認值;但是如果默認是null的話,該屬性就不會被序列化。
java類,我們仍然采用的是MyEntry 類。
MyEntry entry2 = new MyEntry(); entry2.setName("tom"); entry2.setSalary(2999); List<String> hobbies = new ArrayList<>(); hobbies.add("basket"); hobbies.add("tennis"); entry2.setHobbies(hobbies); Map<Integer, String> collections = new HashMap<>(); collections.put(2, "paint"); collections.put(3, "mouse"); entry2.setCollections(collections); Gson gson2 = new Gson(); String json2 = gson2.toJson(entry2); System.out.println(json2); // {"name":"tom","age":0,"money":2999,"hobbies":["basket","tennis"],"collections":{"2":"paint","3":"mouse"}}對于非值屬性,即引用屬性,如hobbies、collections,如果沒有設置值的話,在序列化后的json數據中,是不會出現的。而如果是值屬性的話,沒有設置值的情況下,在json數據中會是使用java中的默認值。
4.1.1 要生成對象形式的json 數據
- 第一種方法是上面的,直接使用java類對象
- 還可以使用生成map對象,進行序列化
4.1.2 要生成數組形式的json 數據
- 第一種,使用String[] 字符串數組來生成
- 還可以使用List對象來序列化
- 還可以使用Set對象來序列化
對于序列化的要求,更多的情況會使用注解來選擇需要/不需要進行序列化的字段。
總結
- 上一篇: JVM实战与原理---内存回收策略
- 下一篇: JAVA中的那些名词解释