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

来源:https://www.cnblogs.com/furenjian/archive/2018/07/28/9382634.html
-Advertisement-
Play Games

(轉自)https://www.cnblogs.com/robbinluobo/p/7217387.html String、JsonObject、JavaBean 互相轉換 User user = new Gson().fromJson(jsonObject, User.class); User u ...


 

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

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數組,也就是今天說的五大招!

在介紹之前先來個約定,比如下麵的這個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

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();

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 效果圖: 參考地址: https://blog.csdn.net/w3chhhhhh/article/details/54097890 ...
  • 1、表和sql的優化 -》大表拆分成小表、分區表、外部表、臨時表都是屬於優化的一塊 -》分區表:檢索更快速 -》外部表:數據安全性 -》臨時表&拆分子表:簡化複雜的SQL以及需求 2、SQL可以從join和fliter兩方面深入 3、MR優化 -》map和reduce的個數 -》一個分片就是一個塊, ...
  • 課程教師:李興華 課程學習者:陽光羅諾 日期:2018-07-28 知識點: 1、 瞭解PL/SQL的主要特點 2、 掌握PL/SQL塊的基本結構 PL/SQL PL/SQL是Oracle在關係資料庫結構化查詢語言SQL基礎上擴展得到的一種過程化查詢語言。 SQL與編程語言之間的不同之處在於,SQL ...
  • 最近很多人都想學習大數據開發,但是卻不知道如何開始學習,今天軟妹子專門整理了一份針對大數據初學者的大數據開發學習路線。 下麵分十個章節來說明大數據開發要學習的內容: 以上就是一個大數據新手,想要學會大數據開發,需要學習的內容,大數據學習是一個持續的過程,只要用心學,沒有學不會的東西哦!我要推薦下我自 ...
  • 一、整體瞭解數據分析新人們被”大數據“、”人工智慧“、”21世紀是數據分析師的時代“等等信息吸引過來,立志成為一名數據分析師,於是問題來了,數據分析到底是乾什麼的?數據分析都包含什麼內容?市面上有很多講數據分析內容的書籍,在此我推薦《深入淺出數據分析》,此書對有基礎人士可稱消遣讀物, 但對新人們還是 ...
  • 占座 ...
  • 本文部分內容來自於網路,點擊瀏覽原文 app:layout_constraintLeft_toLeftOf //Constrains the left side of a child to the left side of a target child (contains the target ch ...
  • 女孩:上海站到了? 男孩:嗯呢?走向世界~ 女孩:Intent核心技術和數據存儲技術? 男孩:對,今日就講這個~ Intent是各個組件之間用來進行通信的,Intent的翻譯為“意圖”的意思,是傳輸數據的核心對象,它可以開啟一個activity,也可以發送廣播消息和開啟Service服務,對於他們之 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...