1. 程式人生 > >關於利用Gson轉json

關於利用Gson轉json

轉]用GSON 五招之內搞定任何JSON陣列
關於GSON的入門級使用,這裡就不提了,如有需要可以看這篇博文 《Google Gson的使用方法,實現Json結構的相互轉換》 ,寫的很好,通俗易懂。

我為什麼寫這篇文章呢?因為前幾晚跟好友 xiasuhuei321 探討了一下GSON解析複雜的JSON的時候,能不能只解析源資料中的陣列,甚至只解析陣列的某一部分。探討了二十分鐘,得出結論:沒用過,不知道。

所以今天特地研究了一下,發現真的So Easy!之前想複雜了,學習的過程中,發現有五種方式分別搞定不同情況的JSON陣列,也就是今天說的五大招!

在介紹之前先來個約定,比如下面的這個JSON:

"muser"
: [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "[email protected]" }, ... ] 這裡的 “muser” ,也就是陣列的名稱,稱它為資料頭,防止跟裡面的 欄位 有歧義; 如果沒有資料頭,那就叫它純資料,或者純陣列資料; 程式碼中用到的 JsonArray/JsonObject 等熟悉的類全部來自 GSON 。 開始過招吧! 第一招 A 沒有資料頭的純陣列JSON如何解析? 根據約定,也就是這個 JSON 裡面只有一個數組(JsonArray),而且這個陣列沒有名字,比如像下面這樣的: [ { "name"
: "zhangsan", "age": "10", "phone": "11111", "email": "[email protected]" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "[email protected]" }, ... ] 這裡其實是最簡單的一種 JSON 陣列格式,強大的 GSON 可以直接解析成一個 List 。但在這裡我先不直接解析,就用比較老實的方法去解析,因為需要引出兩個東西。 首先我們需要建立一個Bean物件,注意變數名要跟欄位名稱一致,沒什麼好說的: public
class UserBean { //變數名跟JSON資料的欄位名需要一致 private String name ; private String age; private String phone; private String email; ... } 下面這是解析過程,先看程式碼: /** * 解析沒有資料頭的純陣列 */ 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 解析成相應的物件。 程式碼本身不難,容易看懂,但前面說到,這裡我故意這樣寫,因為需要說兩個東西: 1、JsonParse 從名稱我們就可以看出,這是一個解析類。沒錯,它可以把 JSON 資料分別通過 getAsJsonObject 和 getAsJsonArray 解析成 JsonObject 和 JsonArray 。這跟普通的解析 JSON 差不多,不展開說。 2、JsonElement 這個類我是第一次見,它是一個抽象類,代表 JSON 串中的某一個元素,可以是 JsonObject/JsonArray/JsonPrimitive/… 中的任何一種元素。 所以在上面的程式碼中,我們可以看到它能把 JsonArray 中的每一個元素轉成 JsonObject ,甚至說它本身就是 JsonObject 。 好了,就為了說這兩個東西。記住,後面將會用到。 來看一下執行的圖吧,很簡單的東西,後面的二三都是這樣的效果,就不重複貼圖了: 第二招 Q 有資料頭的純陣列資料該怎麼解析? 內容跟上面的 JSON 一模一樣,只不過加了一個名稱 “muser” ,也就是約定好的 資料頭 : { "muser": [ { "name": "zhangsan", "age": "10", "phone": "11111", "email": "[email protected]" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "[email protected]" }, ... ] } 有人說,這還不簡單,在第一招中的 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 ,它是什麼呢? 3、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": "[email protected]" }, { "name": "lisi", "age": "20", "phone": "22222", "email": "[email protected]" }, ... ] } 這裡就不再是純陣列資料了,還有兩個湊數的不知道幹嘛用的欄位,這裡也有資料頭,之前用的是笨方法,現在來真正見識一下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": "[email protected]" }, "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 (原文地址:http://www.open-open.com/lib/view/open1472632967912.html) 分類: Java 好文要頂 關注我 收藏該文 HelloSUN 關注 - 4 粉絲 - 49 +加關注 4 0 « 上一篇:[轉]Http Message結構學習總結 » 下一篇:[轉]OkHttp3 最有營養的初級教程 posted @ 2017-03-30 17:20 HelloSUN 閱讀(13646) 評論(0) 編輯 收藏 重新整理

相關推薦

關於利用Gsonjson

轉]用GSON 五招之內搞定任何JSON陣列 關於GSON的入門級使用,這裡就不提了,如有需要可以看這篇博文 《Google Gson的使用方法,實現Json結構的相互轉換》 ,寫的很好,通俗易懂。 我為什麼寫這篇文章呢?因為前幾晚跟好友 xiasuhuei3

利用Gsonjson化成Java List異常問題

Java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to ….. 我需要把一串json轉化成Java List 最初是這樣寫的: private List<Co

Android 利用gsonjson字串陣列陳物件的方法

前提:下載Gson.jar List<DaShangScanPostsBean> persons = new ArrayList(); Gson gson = new Gson();List<JsonElement> list = new Array

利用GsonJSON數據進行格式化(pretty print)

div pretty string類型 overflow jsonp creat () one ons 我們可以利用Gson包將String類型的JSON數據進行格式化。 Gson gson = new GsonBuilder().setPrettyPrinting().

利用JavaScriptSerializerjson實用方法

調用 json align this () sum 直接 解決 nbsp 項目中經常碰到需要輸出的是json數據,使用JavaScriptSerializer轉換,以前老的方法如下。 JavaScriptSerializer jss = new JavaScriptSeri

Android list 泛型 用Gson json字串 出現 java.lang.StackOverflowError異常解決

 不廢話 第一次寫部落格,不知道怎麼寫,  直接進入主題 我來這最熟悉的程式碼 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSt

利用Gsonjson進行flatten(扁平化)處理

目錄 Gson是Google釋出的一個處理json的java庫。通過使用Gson可以將java物件序列化為json字串,或是將json字串反序列化為java物件。 在Gson中,JsonElement是抽象類,由JsonObject、JsonArray、J

Android Gsonjson資料double 數值為0.0的問題

今天上午改需求 遇到一個奇葩的Bug   返回的為double 型別  於是在實體類裡寫private double space; get  set略。。。 但是顯示的時候為0.0  於是將實體類的double 改為String 

fastDFS+LibreOffice多檔案上傳(二)後端部分:檔案資訊json字串儲存資料庫(Gson和org.json兩種方式)

需要注意的地方: 1)如果你複製我的程式碼到你的程式上報錯,可以看看我第一篇文章實體類跟配置檔案的設定:https://blog.csdn.net/qq_36688143/article/details/84162924 第二篇檔案上傳前端頁面的程式碼: https://blog.c

利用Google Gson實現JSON字串和物件之間相互轉換

最近一個專案需要用到JSON,需要在JSON字串和物件之間相互轉換,在網上找了些資料,發現google的Gson還是比較不錯的。 廢話不說,下面是簡單的例子: 先上原始碼:下載(包含jar包) Person實體類 package com.hsun.json; /** * Pe

學習筆記 利用反射 手寫一個簡單的實體類 json 的方法

不得不說 反射真的是個好動  # 貼上我的程式碼   package com.lengff.test; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetExce

利用Gson解析多層巢狀的JSON資料

資料例項: { "error": 0, "status": "success", "results": [ { "currentCity

Android利用Gson庫解析複雜結構的JSON資料

最近在應用Face++進行人臉識別開發時,經常需要解析Face++返回的結構複雜的JSON資料,於是便決定應用Google開發的Gson庫來減輕工作量。 首先給大家看一個比較複雜的JSON資料: {"face":[{"attribute":{"age":{"

利用Gson解析request得到的Json字串陣列,並實現與具體物件間的轉換

當利用request.getParameter()方法得到Json字串陣列後,如果想要將其轉換成需要的Class物件時,可以利用Gson中自帶的一些物件來解析: ArticleBean article = new ArticleBean(); String

GsonjsonList,Listjson

json轉List val mNewsSortList = Gson().fromJson(newsSortConfig, object : TypeToken<List<NewsSo

利用Gson將物件轉換成json,忽略某些欄位的方法

有時我們將物件轉換成json格式的字串時,並不希望裡面所有的欄位都轉換,我們可能希望忽略某些.預設的gson是全部轉換的,為此要給gson做一些配置.其實Gson的官方已經給出示例,如下:官方的示例說明 public @interface FooAnnota

利用Python互Json資料格式

一、將Python物件轉換成json物件 import json def python_to_json(): """ 將python物件轉換成json """ d = {

字典json字符串方法

mutable nbsp bject pla error: tab 空格 字符串 arc [self convertToJsonData:_editDictionary]; /** 字典轉json字符串方法 */ -(NSString *)convertToJsonData

Gson解析json

down googl -s span info 解析 實例 pack targe 以下是我依據Gson對json做的一些解析案例,如今我來說說Gson是如何進行Json解析的。 新建一個project: WeatherDemo,導入Gson包。Gson庫導入完畢之後就開

json字符串json對象,json對象轉換成java對象

對象 apply ebo 獲取 mode ping pub gets get @RequestMapping(value = "updateInvestorApplyAccountNo", method = RequestMethod.POST) @Respo