Gson基本操做,JsonObject,JsonArray,String,JavaBean,List互轉

 

(轉自)https://www.cnblogs.com/robbinluobo/p/7217387.htmlhtml

String、JsonObject、JavaBean 互相轉換 User user = new Gson().fromJson(jsonObject, User.class); User user = new Gson().fromJson(string, User.class); String string = new Gson().toJson(user); JsonObject jsonObject = new Gson().toJsonTree(user).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(string).getAsJsonObject(); String、JsonArray、List互相轉換 List<User> userList = gson.fromJson(string, new TypeToken<List<User>>() {}.getType()); List<User> userList = gson.fromJson(jsonArray, new TypeToken<List<User>>() {}.getType()); String string = new Gson().toJson(userList); JsonArray jsonArray = new Gson().toJsonTree(userList, new TypeToken<List<User>>() {}.getType()).getAsJsonArray(); JsonArray jsonArray = new JsonParser().parse(string).getAsJsonArray();

學習的過程當中,發現有五種方式分別搞定不一樣狀況的JSON數組,也就是今天說的五大招!java

在介紹以前先來個約定,好比下面的這個JSON:git

"muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, ... ]
  • 這裏的 「muser」 ,也就是數組的名稱,稱它爲數據頭,防止跟裏面的 字段 有歧義;
  • 若是沒有數據頭,那就叫它純數據,或者純數組數據;
  • 代碼中用到的 JsonArray/JsonObject 等熟悉的類所有來自 GSON 。

開始過招吧!github

第一招 A

沒有數據頭的純數組JSON如何解析?

根據約定,也就是這個 JSON 裏面只有一個數組(JsonArray),並且這個數組沒有名字,好比像下面這樣的:數據庫

[
  {
    "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ]

這裏實際上是最簡單的一種 JSON 數組格式,強大的 GSON 能夠直接解析成一個 List 。但在這裏我先不直接解析,就用比較老實的方法去解析,由於須要引出兩個東西。json

首先咱們須要創建一個Bean對象,注意變量名要跟字段名稱一致,沒什麼好說的:數組

public class UserBean { //變量名跟JSON數據的字段名須要一致 private String name ; private String age; private String phone; private String email; ... }

下面這是解析過程,先看代碼:markdown

/** * 解析沒有數據頭的純數組 */ private void parseNoHeaderJArray() { //拿到本地JSON 並轉成String String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_1); //Json的解析類對象 JsonParser parser = new JsonParser(); //將JSON的String 轉成一個JsonArray對象 JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray(); Gson gson = new Gson(); ArrayList<UserBean> userBeanList = new ArrayList<>(); //增強for循環遍歷JsonArray for (JsonElement user : jsonArray) { //使用GSON,直接轉成Bean對象 UserBean userBean = gson.fromJson(user, UserBean.class); userBeanList.add(userBean); } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }

從代碼中能夠看出解析的步驟以下:網絡

  • 不管 JSON 來自本地仍是網絡獲取,都要先將 JSON 轉成 String ;
  • 須要一個 JSON 解析類對象將JSON的字符串轉成 JsonArray ,前提是咱們知道 JSON 中只有純數組;
  • 循環遍歷 JsonArray ,並用 GSON 解析成相應的對象。

代碼自己不難,容易看懂,但前面說到,這裏我故意這樣寫,由於須要說兩個東西:post

一、JsonParse

從名稱咱們就能夠看出,這是一個解析類。沒錯,它能夠把 JSON 數據分別經過 getAsJsonObject 和 getAsJsonArray 解析成 JsonObject 和 JsonArray 。這跟普通的解析 JSON 差很少,不展開說。

二、JsonElement

這個類我是第一次見,它是一個抽象類,表明 JSON 串中的某一個元素,能夠是 JsonObject/JsonArray/JsonPrimitive/… 中的任何一種元素。

因此在上面的代碼中,咱們能夠看到它能把 JsonArray 中的每個元素轉成 JsonObject ,甚至說它自己就是 JsonObject 。

好了,就爲了說這兩個東西。記住,後面將會用到。

來看一下運行的圖吧,很簡單的東西,後面的二三都是這樣的效果,就不重複貼圖了:

 

第二招 Q

有數據頭的純數組數據該怎麼解析?

內容跟上面的 JSON 如出一轍,只不過加了一個名稱 「muser」 ,也就是約定好的 數據頭 :

{
  "muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ] }

有人說,這還不簡單,在第一招中的 getAsJsonArray 加一個字符串就是咯,就像這樣:

JsonArray jsonArray = parser.parse(strByJson).getAsJsonArray("muser");

思路是對的,可是不要忘了,數組裝在一個 { } 括起來的 JsonObject 裏。還記得上面的 JsonParse 麼,它的 getAsJsonObject 能夠作到這點,因此代碼就是這樣啦,很簡單就再也不解釋了:

/** * 解析有數據頭的純數組 */ private void parseHaveHeaderJArray() { //拿到本地JSON 並轉成String String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_2); //先轉JsonObject JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); //再轉JsonArray 加上數據頭 JsonArray jsonArray = jsonObject.getAsJsonArray("muser"); Gson gson = new Gson(); ArrayList<UserBean> userBeanList = new ArrayList<>(); //循環遍歷 for (JsonElement user : jsonArray) { //經過反射 獲得UserBean.class UserBean userBean = gson.fromJson(user, new TypeToken<UserBean>() {}.getType()); userBeanList.add(userBean); } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }

注意,這裏又引出了一個東西: TypeToken ,它是什麼呢?

三、TypeToken

這個東西頗有意思,原本我不知道到是幹嗎的,看了看源碼,看不懂。後來無心發現它所在的包:

import com.google.gson.reflect.TypeToken;

哎喲我去, reflect 這不是反射麼,一會兒就明白了。沒錯,它實際上是一個匿名內部類,看一下官方解釋:

GSON 提供了 TypeToken 這個類來幫助咱們捕獲(capture)像 List 這樣的泛型信息。Java編譯器會把捕獲到的泛型信息編譯到這個匿名內部類裏,而後在運行時就能夠被 getType() 方法用反射的 API 提取到。

解釋的很官方,實際上就是一句 通俗但不嚴謹 的話,它將泛型 T 轉成 .class 。好比上面的 TypeToken 通過 getType() 後就是 UserBean.class 。

好了,說到這裏基本鋪墊就完成了,再次強調一下:

對於上面的 JSON 徹底能夠直接經過 GSON 轉成 List ,不用這麼麻煩,我只是爲了引出3個小知識。

第三招 W

有數據頭的複雜數據該如何解析呢?

簡單的說完了,鋪墊也鋪完了,來看一看複雜的吧:

{
  "code": 200, "msg": "OK", "muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "11111@11.com" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "22222@22.com" }, ... ] }

這裏就再也不是純數組數據了,還有兩個湊數的不知道幹嗎用的字段,這裏也有數據頭,以前用的是笨方法,如今來真正見識一下GSON的威力吧。

第一步根據 JSON 創建 Bean ,注意這裏的 Bean 是返回全部字段,由於 GSON 能直接解析成 List ,因此 Bean 是下面這樣的,一樣把佔地方的 get/set 省略:

/** * Created by xiarui on 2016/8/30. * 返回全部結果的Bean */ public class ResultBean { //注意變量名與字段名一致 private int code; private String msg; private List<UserBean> muser; public class UserBean{ private String name ; private String age; private String phone; private String email; ... } ... }

注意,這個 ResultBean 裏面有一個 UserBean 。 它雖然跟上面第一第二招雖然內容同樣,可是做用不同,這是做爲 JsonArray 解析後存入 List 中的對象。

算了,有點拗口,直接上代碼吧:

/** * 有消息頭 複雜數據 常規方式 */ private void parseComplexJArrayByCommon() { //拿到Json字符串 String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3); //GSON直接解析成對象 ResultBean resultBean = new Gson().fromJson(strByJson,ResultBean.class); //對象中拿到集合 List<ResultBean.UserBean> userBeanList = resultBean.getMuser(); //展現到UI中 mainLView.setAdapter(new ResultAdapter(this, userBeanList)); }

沒錯,就是這麼四句話搞定第一二招的內容。看出GSON的強大了吧,固然若是有人想不開只寫一句話的話:

mainLView.setAdapter(new ResultAdapter(this,new Gson().fromJson(JsonToStringUtil.getStringByJson(this,R.raw.juser_3),ResultBean.class).getMuser()));

我也是沒意見的,不過請對本身好一點,謝謝。

第四招 E

只想解析複雜JSON中的數組或數組中的某部份內容怎麼辦?

好了,來到重點了,這也是跟好友 xiasuhuei321 沒有討論出來的狀況。

仍是上面的JSON數據,這裏爲了篇幅就不貼重複代碼了,假如我只想取 「muser」 這個數組中的年齡(age)大於30歲的怎麼辦?

OK,固然能夠先所有解析,再從 List 中取。那假如我有一萬條數據呢?所有解析不是很麻煩呢?

因此一個思路就是第一二招中說的: 遍歷!

OK,你會問先遍歷還不是要讀一萬條,是的,仍是要讀一萬條,可是假如我要把這些存入數據庫呢?假如一萬條數據中只有一條符合條件,難道我先存一萬條,再從數據庫中查詢麼?

固然這種狀況是極端狀況,但也說明了一個問題,不能全部狀況下都先所有解析,假若有一萬個字段,Bean還得寫多長…可怕。

如今來講一下完整的思路,也是我學習中思考的過程:

  • 第一點確定就是剛纔提到的遍歷,這個很好理解,因此咱們先要取這一個數組(JsonArray),那麼如何取呢?還記得以前提到的 JsonParse 麼,它的 getAsJsonArray() 能夠傳入 數據頭 拿到數組,固然不要忘了最外面一層是個 JsonObject 。
    //最外層 JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); //須要遍歷的數組 JsonArray jsonArray = jsonObject.getAsJsonArray("muser");
  • 拿到數組之後,咱們就能夠遍歷了,通過第一二招的洗禮,相信在遍歷上,應該沒什麼問題了,使用的仍是以前提到的 JsonElement 。
    //循環遍歷數組 for (JsonElement user : jsonArray) { UserBean userBean = new Gson().fromJson(user, new TypeToken<UserBean>() {}.getType()); //根據條件過濾 if (Integer.parseInt(userBean.getAge()) > 30) { userBeanList.add(userBean); } }
  • 上面的代碼很簡單,也用到了以前提到的 TypeToken ,什麼意思就不用解釋了吧。

好了,完整的代碼以下:

/** * 有數據頭 複雜數據 截取方式 */ private void parseComplexJArrayByDirect() { //拿到JSON字符串 String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_3); List<UserBean> userBeanList = new ArrayList<>(); //拿到數組 JsonObject jsonObject = new JsonParser().parse(strByJson).getAsJsonObject(); JsonArray jsonArray = jsonObject.getAsJsonArray("muser"); //循環遍歷數組 for (JsonElement user : jsonArray) { UserBean userBean = new Gson().fromJson(user, new TypeToken<UserBean>() { }.getType()); //根據條件過濾 if (Integer.parseInt(userBean.getAge()) > 30) { userBeanList.add(userBean); } } mainLView.setAdapter(new UserAdapter(this, userBeanList)); }

運行的結果圖以下:

 

能夠看到,如今咱們作到了只取 JSON 數據中數組中某一部分了。那麼擴展一下,只取 JSON 數據中的某一個數組中的某一個字段呢?固然能夠實現,不過仍是留給你們本身思考吧,固然下面反人類的第五招也是能夠解決這個問題的。

第五招 R

若是一個 JSON 數據很很很複雜怎麼解析?

什麼叫作複雜,這裏我簡單寫了個比較複雜的,有數據頭,一層嵌套一層,我尚未寫數組呢:

{
  "group": { "user": { "name": "張三", "age": "10", "phone": "11111", "email": "11111@11.com" }, "info": { "address": "北京", "work": "Android Dev", "pay": "10K", "motto": "先定一個小目標,好比我先賺一個億" } } }

三種方式解析:

  • 第三招,所有解析出來;
  • 第四招,要什麼解析什麼;
  • 第五招,反人類的 JsonReader 。

至於爲何反人類,很差說。你們看代碼就知道了,代碼很簡單,跟 XML 的解析差很少,是根據節點來的,至於怎麼用,仍是那句話直接看代碼吧,確實處理起來邏輯清晰,可是代碼量上,真的不敢恭維。

只貼代碼不做解釋,如想詳細瞭解,看文末連接。

/** * 經過JsonReader的方式去解析 */ private void parseComplexJArrayByReader() throws IOException { String strByJson = JsonToStringUtil.getStringByJson(this, R.raw.juser_4); JsonReader reader = new JsonReader(new StringReader(strByJson)); try { reader.beginObject(); String tagName = reader.nextName(); if (tagName.equals("group")) { //讀group這個節點 readGroup(reader); } reader.endObject(); } finally { reader.close(); } } /** * 讀group這個節點 * * @param reader JsonReader */ private void readGroup(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tagName = reader.nextName(); if (tagName.equals("user")) { readUser(reader); } else if (tagName.equals("info")) { readInfo(reader); } } reader.endObject(); } /** * 讀用戶基本消息 user節點 * * @param reader JsonReader */ private void readUser(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tag = reader.nextName(); if (tag.equals("name")) { String name = reader.nextString(); nameText.setText(name); } else if (tag.equals("age")) { String age = reader.nextString(); ageText.setText(age); } ... else { reader.skipValue();//忽略 } } reader.endObject(); } /** * 讀用戶其餘消息 info節點 * * @param reader JsonReader */ private void readInfo(JsonReader reader) throws IOException { reader.beginObject(); while (reader.hasNext()) { String tag = reader.nextName(); if (tag.equals("address")) { String address = reader.nextString(); addressText.setText(address); } else if (tag.equals("work")) { String work = reader.nextString(); workText.setText(work); } ... else { reader.skipValue();//忽略 } } reader.endObject(); }

 

五招過完,多謝指教!

總結

以上幾乎就是 JSO N數組的全部狀況了,這五招也幾乎能所有搞定!不得不說,GSON 確實比較強大,強大在於能夠將 JSON 直接解析成對象,比之前的手動去解析方便太多,固然 fastJson 也能實現這點,可是這東西仍是官方的用的順手。

在學習的過程當中,也是一步一步來的,因此文章也是學習的過程,從簡單的例子學到關鍵內容,再解決複雜狀況。因爲文章寫得倉促,若有疑問或錯誤,歡迎交流與指正,謝謝!

參考資料

靈活組裝Json的數據使用Gson的JsonParser和JsonReader解析Json詳解例子

使用Gson解析複雜的json數據 – tkwxty

JsonElement的簡單說明 – chunqiuwei

Java進階(四)Java反射TypeToken解決泛型運行時類型擦除的有關問題解決

項目源碼

GsonArrayDemo – IamXiaRui – Github

String、JsonObject、JavaBean 互相轉換 User user = new Gson().fromJson(jsonObject, User.class); User user = new Gson().fromJson(string, User.class); String string = new Gson().toJson(user); JsonObject jsonObject = new Gson().toJsonTree(user).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(string).getAsJsonObject(); String、JsonArray、List互相轉換 List<User> userList = gson.fromJson(string, new TypeToken<List<User>>() {}.getType()); List<User> userList = gson.fromJson(jsonArray, new TypeToken<List<User>>() {}.getType()); String string = new Gson().toJson(userList); JsonArray jsonArray = new Gson().toJsonTree(userList, new TypeToken<List<User>>() {}.getType()).getAsJsonArray(); JsonArray jsonArray = new JsonParser().parse(string).getAsJsonArray();
相關文章
相關標籤/搜索