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、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時,取出string
String sex = object.get("sex").getAsString(); System.out.println("sex:" + sex);
// 2. value為array時,取出array
JsonArray 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時,取出object
JsonObject 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)。
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時,取出string
String array_1 = array.get(0).getAsString();
System.out.println("array_1:"+array_1);
// 2. value為int時,取出int
int array_2 = array.get(1).getAsInt();
System.out.println("array_2:"+array_2);
// 3. value為object時,取出object
JsonObject 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時,取出array
JsonArray 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);
1. json
是對象類型
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的規范和常理。
1.2 字段名并不一致怎么辦?
如果前端傳過來的json
數據的key和我們java類的字段不一致,就需要我們在java類中手工進行指定。
@SerializedName()
注解
比如對于上面的json
數據,salary
改成money
,我們得到的java對象中,salary
就會變成默認值:0。
因此,我們要使用注解:
@SerializedName("money")
private String salary;
@SerializedName({"money", "salary"}) // 可以有多個備選值
private String salary;
1.3 如何限定某個字段不參加序列化或反序列化?
@Expose()注解
如果想要讓java類的某些字段不參加序列化或反序列化,可以顯示來設置。如:
@Expose(serialize=false,deserialize=false)
private String name;
上面的name
字段將不參加序列化及反序列化。
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. json
是數組類型
1.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);
1.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<T>
來映射json
數據,使用MyEntry
類來映射json
數據的data
部分。這意味著,對于不同的json數據,我們將不再生成多個java類,而是動態生成所需的java對象。
result對象
public class Result<T>{
public int code;
public String message;
public T data;
// getter、setter
}
1.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);
1.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對象。
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中的默認值。
1.1 要生成對象形式的json
數據
- 第一種方法是上面的,直接使用java類對象
- 還可以使用生成map對象,進行序列化
1.2 要生成數組形式的json
數據
- 第一種,使用
String[]
字符串數組來生成 - 還可以使用List對象來序列化
- 還可以使用Set對象來序列化
對于序列化的要求,更多的情況會使用注解來選擇需要/不需要進行序列化的字段。