zoukankan      html  css  js  c++  java
  • java解析Json字符串之懒人大法

      面对Java解析Json字符串的需求,有很多开源工具供我们选择,如googleGson、阿里巴巴的fastJson。在网上能找到大量的文章讲解这些工具的使用方法。我也是参考这些文章封装了自己的Json解析工具类。这个工具类可以完成Json字符串和对应的实体类对象间的相互转换。用着挺方便的,所以我们之间一直相安无事。直到有一天我遇到了一个新的Json字符串解析需求

    nodesInService”的值从下面的Json字符串中解析出来。

    {

      "beans" : [ {

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

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

        "StorageTypeStats" : [ {

          "key" : "DISK",

          "value" : {

            "blockPoolUsed" : 26618108614,

            "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个元素的值、所有元素值或者与另一个元素相关联的元素值。这些场景的需求,使用相似的思路也是可以实现的。

  • 相关阅读:
    老李分享:持续集成学好jenkins之解答疑问
    持续集成:TestNG组织如何测试用例 1
    老李分享:持续集成学好jenkins之Git和Maven配置 2
    老李分享:持续集成学好jenkins之Git和Maven配置 1
    老李分享:持续集成学好jenkins之内置命令
    老李分享:持续集成学好jenkins之解答疑问
    老李分享:持续集成学好jenkins之安装
    老李分享:接口测试之jmeter
    老李推荐:破坏性创新第一原则 2
    Logback 日志策略配置
  • 原文地址:https://www.cnblogs.com/standup/p/9015997.html
Copyright © 2011-2022 走看看