踩坑系列之--Fastjson JSONPath解析Boolean类型翻车了

2,820 阅读2分钟

1. 现象

不上代码的例子都是耍流氓,我们直接上代码,有如下两个json串,第一个json比第二个json多了两个boolean类型值,以及一个string类型值;

{
	"boolean1":true,
	"boolean2":false,
	"boolean3":true,// 比下面的json多的
	"boolean4":true,// 比下面的json多的
	"name":"str",
	"name1":"str"
}

{
	"boolean1":true,
	"boolean2":false,
	"name":"str"
}
public static void main(String[] args) {
        JSONObject sourceJson = JSON.parseObject("{\n" +
                "\t\"boolean1\":true,\n" +
                "\t\"boolean2\":false,\n" +
                "\t\"boolean3\":true,\n" +
                "\t\"boolean4\":true,\n" +
                "\t\"name\":\"str\",\n" +
                "\t\"name1\":\"str\"\n" +
                "}");

        // 初始配置中,新增的字段添加的库中
        Map<String, Object> paths = JSONPath.paths(sourceJson);
        System.out.println(JSON.toJSONString(paths));

        JSONObject destJson = JSON.parseObject("{\n" +
                "\t\"boolean1\":true,\n" +
                "\t\"boolean2\":false,\n" +
                "\t\"name\":\"str\"\n" +
                "}");

        for (Map.Entry<String, Object> stringObjectEntry : paths.entrySet()) {
            if(stringObjectEntry.getValue() instanceof JSONObject || stringObjectEntry.getValue() instanceof JSONArray){
                continue;
            }
            if (!JSONPath.contains(destJson, stringObjectEntry.getKey())) {
                JSONPath.set(destJson, stringObjectEntry.getKey(), stringObjectEntry.getValue());
                System.out.println("key=" + stringObjectEntry.getKey() + " ,value=" + stringObjectEntry.getValue());
            }
        }

        System.out.println(destJson.toJSONString());
    }

1.1 目标

运行上述代码,这里目标是通过JSONPath解析第一个json,然后对比第二个json中JSONPath,将第一个的多的key,找出来,那正确的情况应该是找出如下几项

{
	"boolean3":true,
	"boolean4":true,
	"name1":"str"
}

1.2 实际情况

  • 1.2.1 代码运行结果如下,可以看到,实际找出的差异键只有两个 boolean3和name1,发现少识别了一个boolean4的key

{"/name":"str","/boolean3":true,"/name1":"str","/boolean2":false,"/":{"boolean2":false,"name":"str","boolean3":true,"boolean1":true,"name1":"str","boolean4":true}}
-----------------
key=/boolean3 ,value=true
key=/name1 ,value=str
-----------------
{"boolean2":false,"name":"str","boolean3":true,"boolean1":true,"name1":"str"}

2. 原因分析

  • 2.1 源码debug

    从运行结果的第一行输出可以看到,解析第一个json串的JSONPath答应出来后,就已经没有了boolean4的存在,所以我们直接debug进去看看到底哪里出了问题??

  • 2.1.1 IDEA断点运行进入JSONPath.paths(sourceJson)方法,如下图

    截屏2020-02-29下午9.21.01.png

  • 2.1.2 代码问题分析

    • 如上图所示,values变量中存储了json的值为key,JsonPath为value,这种情况下,两个boolean类型的json key,value都为true,那么执行到图中代码的571行时,p != null 为true,进入图中画红线框的地方,如下图
      截屏2020-02-29下午9.28.28.png
    • 从上图可以看到,boolean4的path由于Boolean不属于String,Number,Date,UUID,导致被return了,问题原因找到了,就是由于代码中没有把Boolean当做是基础类型导致的,我也去github中寻找是否存在此issue,果然有github issue

3. 解决方法

  • 3.1 版本升级

    • 目前最新的版本1.2.62依然存在此问题所以无法通过升级来解决
  • 3.2 曲线救国

    • 我们可以把Boolean类型的json的value值都加上"",这样就变成了String基础类型,就不会出现上述问题,完美

2020-06-15 更新,目前最新版本1.2.71已经修复上述问题,请更新食用

转载请注明出处 阿布的夏天