java解析Json字符串之懶人大法

  面對Java解析Json字符串的需求,有不少開源工具供咱們選擇,如googleGson、阿里巴巴的fastJson。在網上能找到大量的文章講解這些工具的使用方法。我也是參考這些文章封裝了本身的Json解析工具類。這個工具類能夠完成Json字符串和對應的實體類對象間的相互轉換。用着挺方便的,因此咱們之間一直相安無事。直到有一天我遇到了一個新的Json字符串解析需求node

nodesInService」的值從下面的Json字符串中解析出來。apache

{json

  "beans" : [ {數組

    "name" :"Hadoop:service=NameNode,name=BlockStats",函數

    "modelerType" :"org.apache.hadoop.hdfs.server",工具

    "StorageTypeStats" : [ {oop

      "key" : "DISK",google

      "value" : {spa

        "blockPoolUsed" : 26618108614,server

        "capacityRemaining" : 204199376575,

        "capacityTotal" : 280360910848,

        "capacityUsed" : 26618108614,

        "nodesInService" : 4

      }

    } ]

  } ]

}

  按照一向的作法,須要根據Json字符串的結構定義一個實體類,而後使用Json解析工具類將這個Json字符串映射成對應實體對象,再從對象中將「nodesInService」的值讀出來。

  這Json字符串看起來結構挺複雜的,數組和對象相互嵌套。此外需求只想要「nodesInService」這一個元素的值,其餘元素都不關心。此時個人懶癌無可救藥的發做了。感受爲了一個值就要:定義+映射+讀取...。有點興師動衆有木有?小題大做有木有?殺雞用了牛刀有沒有?

  我只想要一個接口,把原始Json字符串和須要的元素名稱傳入,接口自動解析出元素的值返回給我。幸虧Json字符串的結構看似複雜,其實只有兩種元素類型「JSONObject」和「JSONArray」。無論這兩種類型數據如何嵌套,只要知道元素類型和名稱就能解析出來。因此理論上只要從根元素開始,告訴接口每一級元素的類型和名稱,程序就能按圖索驥將最後一個元素的值提取出來。

 依據以上思路制定了一個元素描述規則:

  1) Json元素描述規則:

    「元素類型:元素名稱,使用「:」分隔。

  2) 類型描述規則:

    AJSONArray

    EJSONObject

  3) 元素描述項之間使用「,」間隔。根元素到目標元素描述項從左向右排列。例如上面的nodesInService」元素的描述項字符串是「A:beans,A:StorageTypeStats,E:value,E:nodesInService」。

  使用Gson解析工具實現Json字符串解析函數源碼以下:

    /**

     * json字符串解析函數

     *

     * @param targetNames

     *            目標名字,由「目標類型:目標名稱」,以「,」間隔

     *            目標類型: AJSONArray

     *                       EJSONObject,如{"name":"value"}

     *            例如: "A:beans,A:StorageTypeStats,E:value,E:nodesInService"

     * @param rawJson

     *            Json字符串

     * @return

     *            最後target對應的值

     */

    public static String parseJson(String targetNames, String rawJson) {

        String retValue = null;

 

        String[] names = targetNames.split(",");

        if (names.length <= 0) {

            System.out.println("Error: parameter \"targetNames\" is invalid!");

            return retValue;

        }

 

        try {

            JsonParser parser = new JsonParser();  //建立json解析器

            JsonObject json = (JsonObject) parser.parse(rawJson);  //建立jsonObject對象

            JsonArray jarray = null;

            for (int i=0; i < names.length -1; i++) {

                System.out.println(names[i]);

                String[] subName = names[i].split(":");

                if (subName.length != 2) {

                    System.out.println("Error: parameter \""+ names[i] + "\" is invalid!");

                    return retValue;

                }

 

                String type = subName[0];

                String jName = subName[1];

 

                switch (type) {

                    case "A":

                        if (null == jarray && null != json) {

                            jarray = json.getAsJsonArray(jName);

                            json = null;

                        }

                        else if (null != jarray && null == json) {

                            JsonElement element = jarray.get(0);

                            JsonObject json1 = element.getAsJsonObject();

                            jarray = json1.getAsJsonArray(jName);

                            json = null;

                        }

                        else {

                            System.out.println("Error: parse json string failed!");

                            return retValue;

                        }

                        break;

                    case "E":

                        if (null == jarray && null != json) {

                            JsonElement element = json.get(jName);

                            json = element.getAsJsonObject();

                            jarray = null;

                        }

                        else if (null != jarray && null == json) {

                            JsonElement element = jarray.get(0);

                            JsonObject json1 = element.getAsJsonObject();

                            json = json1.getAsJsonObject(jName);

                            jarray = null;

                        }

                        else {

                            System.out.println("Error: parse json string failed!");

                            return retValue;

                        }

                        break;

                    default:

                        System.out.println("Error: json type \"" + type + "\" is invalid!");

                        return retValue;

                }

            }

 

            String[] subName = names[names.length-1].split(":");

            if (subName.length != 2) {

                System.out.println("Error: parameter \"targetNames\" is invalid!");

                return retValue;

            }

 

            String jName = subName[1];

 

            if (null != jarray && null == json) {

                JsonElement ele = jarray.get(0);

                if (null != ele) {

                    JsonObject jo = ele.getAsJsonObject();

                    if (null != jo) {

                        retValue = jo.get(jName).getAsString();

                    }

                }

                return retValue;

            }

            else if (null == jarray && null != json) {

                retValue = json.get(jName).getAsString();

            }

            else {

                System.out.println("Error: parse \"" + jName + "\" failed!");

            }

        }catch (JsonIOException e) {

            e.printStackTrace();

        } catch (JsonSyntaxException e) {

            e.printStackTrace();

        }

 

        return retValue;

}

 

  該函數的功能能夠知足這個特定場景的需求,只要將從根元素到目標元素的描述信息字符串和原始Json字符串傳入,函數能夠直接將目標元素的值解析出來,返回給調用者。使用方式比之實體類映射模式更簡潔一些。

  細心的小夥伴看了源碼可能說「你這個函數不行啊,我要的目標元素是整型或浮點型時,你給我一個String返回值算怎麼回事?」,其實不區分元素類型統一返回String類型是爲了簡化描述規則和函數實現的複雜度。相較在描述規則中增長類型描述,由調用者作一次類型轉換更簡單一些。

  另外一位小夥伴又說了「你這個函數有bug, 裏面的魔鬼數字將數組類型元素的取值限定在第一個元素上了」。沒錯,源碼確實有這個限制。形成這種現象的緣由是我遇到的需求中,全部的數組元素都只有一個值。因此個人懶癌又發做了一次,沒有實現更多的預設場景,例如,解析出數組中第N個元素的值、全部元素值或者與另外一個元素相關聯的元素值。這些場景的需求,使用類似的思路也是能夠實現的。

相關文章
相關標籤/搜索