Json是一種輕量級的數(shù)據(jù)交換語言,以文字為基礎(chǔ),且易于讓人閱讀和編寫铣猩,同時也易于機(jī)器解析和生成,因而在客戶端與服務(wù)器交互中得到廣泛應(yīng)用茴丰。但Json自帶的解析類用起來卻差強(qiáng)人意达皿,所以市面上因運(yùn)而生了很多Json轉(zhuǎn)換利器,本文主要介紹其中之一Gson贿肩。Gson是google發(fā)布的library峦椰,主要為了方便將Java對象序列化Serialization至輕量化的封包格式JSON,提供了很多方便快捷的方法汰规。
通過gradle導(dǎo)入包
登錄網(wǎng)站MVNRepository汤功,在搜索框中搜索gson,即可出現(xiàn)各種不同的版本溜哮,選擇gradle下需要的版本滔金,并復(fù)制到gradle文件中即可。
Gson基本用法
Gson提供了兩個方法直接用于解析和生成方法茬射,二者都有重載方法:
- fromJson():實(shí)現(xiàn)反序列化
- toJson():實(shí)現(xiàn)序列化
基本數(shù)據(jù)類型的生成
Gson gson = new Gson();
String jsonNumber = gson.toJson(100); // 100
String jsonBoolean = gson.toJson(false); // false
String jsonString = gson.toJson("String"); //"String"
POJO類的生成與解析
對于普通Java類:
public class User {
public String name;
public int age;
}
生成JSON
Gson gson = new Gson();
User user = new User("Sunny",24);
String jsonObject = gson.toJson(user); // {"name":"Sunny","age":24}
解析JSON
Gson gson = new Gson();
String jsonString = "{\"name\":\"sunny\",\"age\":24}";
User user = gson.fromJson(jsonString, User.class);
注:POJO(Plain Old Java Object)表示普通Java對象鹦蠕,不是JavaBean,EntityBean或者SessionBean在抛。POJO不擔(dān)當(dāng)任何特殊的角色钟病,也不實(shí)現(xiàn)任何特殊的Java框架的接口。
Gson中的泛型
當(dāng)我們解析Json數(shù)組時刚梭,一般有兩種方式:使用數(shù)組肠阱,使用List。而List對于增刪都比較方便朴读,所以實(shí)際用List較多
數(shù)組
String[] strings = gson.fromJson(jsonArray, String[].class);
但對于List將上面代碼中的 String[].class
屹徘,不能直接改為List<String>.class
。對于Java來說 List<String>
和List<User>
這兩個字節(jié)碼文件只有一個衅金,就是 List.class
噪伊,這就是Java泛型使用時要注意的泛型擦除問題簿煌。
List
為了解決上述問題,Gson提供TypeToken
來實(shí)現(xiàn)對泛型的支持鉴吹。TypeToken 這個類幫助我們捕獲(capture)像 List 這樣的泛型信息姨伟。Java編譯器會把捕獲到的泛型信息編譯到這個匿名內(nèi)部類里,然后在運(yùn)行時就可以被 getType() 方法用反射的 API 提取到豆励。也就是將泛型T轉(zhuǎn)成 .class
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
注:TypeToken
的構(gòu)造方法是protected
修飾的,所以上面才會寫成new TypeToken<List<String>>() {}.getType()
而不是new TypeToken<List<String>>().getType()
@Expose夺荒、@SerializeName注解的使用
Json解析的字段和值得名稱和類型是一一對應(yīng)的,但有時前端和后臺使用的語言不同良蒸,二者語言規(guī)范風(fēng)格不同技扼,命名時常常會出現(xiàn)不和諧的地方。這時 @Expose @SerializeName 兩個注解就要發(fā)揮他們的作用啦
- @Expose注解:區(qū)分實(shí)體中不想被序列化的屬性嫩痰,其自身包含兩個屬性deserialize(反序列化)和serialize(序列化)剿吻,默認(rèn)都為true
- @SerializeName注解:定義屬性序列化后的名稱
使用 new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();創(chuàng)建Gson對象,沒有@Expose注釋的屬性將不會被序列化.始赎。另外想要不序列化某個屬性和橙,也可以使用transient。
Gson在序列化和反序列化時需要使用反射造垛,說到反射就想到注解,一般各類庫都將注解放到annotations包下魔招,打開源碼在com.google.gson包下有一個annotations類,其中有一個SerializedName的注解類五辽,這就是我們用到的办斑。
Gson解析復(fù)雜Json數(shù)據(jù)
首先,要知道兩個類:
1杆逗、JsonParse
從名稱我們就可以看出乡翅,這是一個解析類。沒錯罪郊,它可以把 JSON 數(shù)據(jù)分別通過getAsJsonObject
和getAsJsonArray
解析成JsonObject
和JsonArray
蠕蚜。這跟普通的解析 JSON 差不多。
2悔橄、JsonElement
是一個抽象類靶累,代表 JSON 串中的某一個元素,可以是JsonObject/JsonArray/JsonPrimitive/...
中的任何一種元素癣疟。
沒有數(shù)據(jù)頭的純數(shù)組
JSON里面只有一個數(shù)組挣柬,而數(shù)組中沒有名字:
[
{
"name": "zhangsan",
"age": "10",
"phone": "11111",
"email": "11111@11.com"
},
{
"name": "lisi",
"age": "20",
"phone": "22222",
"email": "22222@22.com"
},
...
]
開始解析,首先定義一個用戶類:
public class UserBean {
//變量名跟JSON數(shù)據(jù)的字段名需要一致
private String name ;
private String age;
private String phone;
private String email;
...
}
方法一:Gson可以直接解析成一個List
List<UserBean> userList = gson.fromJson(jsonStr, new TypeToken<List<UserBean>>(){}.getType());
方法二:傳統(tǒng)老實(shí)方法
//Json的解析類對象
JsonParser parser = new JsonParser();
//將JSON的String 轉(zhuǎn)成一個JsonArray對象
JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray();
Gson gson = new Gson();
ArrayList<UserBean> userBeanList = new ArrayList<>();
//加強(qiáng)for循環(huán)遍歷JsonArray
for (JsonElement user : jsonArray) {
//使用GSON睛挚,直接轉(zhuǎn)成Bean對象
UserBean userBean = gson.fromJson(user, UserBean.class);
userBeanList.add(userBean);
}
有數(shù)據(jù)頭的純數(shù)組數(shù)據(jù)
{
"user": [
{
"name": "zhangsan",
"age": "10",
"phone": "11111",
"email": "11111@11.com"
},
{
"name": "lisi",
"age": "20",
"phone": "22222",
"email": "22222@22.com"
},
...
]
}
開始解析:
//先轉(zhuǎn)JsonObject
JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject();
//再轉(zhuǎn)JsonArray 加上數(shù)據(jù)頭
JsonArray jsonArray = jsonObject.getAsJsonArray("user");
Gson gson = new Gson();
ArrayList<UserBean> userBeanList = new ArrayList<>();
//循環(huán)遍歷
for (JsonElement user : jsonArray) {
//通過反射 得到UserBean.class
UserBean userBean = gson.fromJson(user, new TypeToken<UserBean>() {}.getType());
userBeanList.add(userBean);
}
有數(shù)據(jù)頭的復(fù)雜數(shù)據(jù)
{
"code": 200,
"msg": "OK",
"user": [
{
"name": "zhangsan",
"age": "10",
"phone": "11111",
"email": "11111@11.com"
},
{
"name": "lisi",
"age": "20",
"phone": "22222",
"email": "22222@22.com"
},
...
]
}
開始解析:
第一步:根據(jù) JSON 建立 Bean 邪蛔,注意這里的 Bean 是返回所有字段,因為 GSON 能直接解析成 List 扎狱,同時把 get/set 省略侧到。
public class ResultBean {
//注意變量名與字段名一致
private int code;
private String msg;
private List<UserBean> user;
public class UserBean{
private String name ;
private String age;
private String phone;
private String email;
...
}
...
}
注意:這個類中有一個UserBean勃教,也可以定義在外面,可以作為JsonArray解析后存入List中的對象床牧。
//GSON直接解析成對象
ResultBean resultBean = new Gson().fromJson(strByJson,ResultBean.class);
//對象中拿到集合
List<ResultBean.UserBean> userBeanList = resultBean.getUser();
另外荣回,變量名與字段名不一致也可以,因為Json中字段通常為下劃線方式戈咳,而Java中字段通常為駝峰方式,故需要能夠轉(zhuǎn)換對應(yīng)壕吹,而Gson也有相關(guān)功能著蛙,例如:
public class UserBean {
@SerializeName("user_name")
private String userName;
@SerializeName("user_age")
private String userAge;
}
工具推薦
jsonschema2pojo:根據(jù)JSON結(jié)構(gòu)產(chǎn)生POJO對象
參考資料
Gson User Guide
通透Gson@Expose注解、@SerializedName哎迄、解析json數(shù)據(jù)
Android:用GSON 五招之內(nèi)搞定任何JSON數(shù)組
你真的會用Gson嗎?Gson使用指南(一)