FastJson 处理json数据中对象相互引用,最后转为json字符串出现占位符("$ref"标识循环引用)"的问题

环境

fastjson 1.2.41

问题说明

FastJson 问题
在json对象中有多个地方引用了相同的对象,在经过几次转换转为json字符串的时候会出现占位符,
然后使用fastjson 解析字符串也能正确解析,但使用其他json类库解析,无法正常还原数据,还是占位符

测试代码

/**
     * FastJson 问题
     * 测试 JSONArray(几个元素有关联,引用了相同得对象) -> 转为List -> 加入到 JSONObject 中 -> 最后转为 json 字符串 打印的时候(最后一步得时候会出现占位符)
     * -> 然后再转为 JSONObject 的时候,非FastJson解析会出现问题(fastJson 解析正常,但是其他json类库处理时,不会对占位符处理,最后直接就原样的将值解析成占位符)
     * 测试
     * testTransfer1  仅仅数据一样,但是实际上是几个不同的对象(数据相同,对象不同),经过上述变化,未出现占位符
     * testTransfer2  是从某一元素上取得数据(同一个对象,在json对象中,多个地方都有引用)在添加到该jsonArray 上,经过上述变化,会出现占位符
     */
    @Test
    public void name() {
//        testTransfer1();
        testTransfer2();
    }

    private void testTransfer1() {
//        [{"one":1,"two":2,"tickets":[{"one":2,"two":3},{"one":3,"two":4}]},{"one":2,"two":3},{"one":3,"two":4}]

        String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]},{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]";
        JSONArray array = JSON.parseArray(str);
        List<Object> objects = array.toJavaList(Object.class);

        JSONObject object = new JSONObject();
        object.put("list", objects);
        System.out.println(object);

        // 经过测试发现如果,不直接用从某个元素中取数据,在添加到该jsonArray 本身,即使他们数据有重合的(数据相同,但不是同一个对象),也不会出现 占位符的现象
    }


    private void testTransfer2() {
//         [{"one":1,"two":2,"tickets":[{"one":2,"two":3},{"one":3,"two":4}]]

        String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]}]";
        JSONArray array = JSON.parseArray(str);
        // 这里添加
        JSONArray tickets = array.getJSONObject(0).getJSONArray("tickets");
        for (int i = 0; i < tickets.size(); i++) {
            array.add(tickets.get(i));
        }

        List<Object> list = array.toJavaList(Object.class);

//      以下代码说明 FastJson 在之后 转为 json 字符串 ,然后再解析为 json 对象时处理正常(能正常解析)
        JSONObject object = new JSONObject();
        object.put("list",list);
        String jsonStr = object.toJSONString();
        System.out.println(jsonStr);
        JSONArray list1 = JSON.parseObject(jsonStr).getJSONArray("list");
        System.out.println(list1);

        // 切换 为 其他 json类库处理,例如:jackson
        ObjectMapper mapper = new ObjectMapper();
        try {
            Object o = mapper.readValue(jsonStr, Object.class);
            System.out.println(o);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        // 内部 从 某一个 元素取出数据,在添加到 jsonArray 上, 经过 上述转换 (JSONArray(几个元素有关联) -> 转为List -> 加入到 JSONObject 中 -> 转为 json 字符串),最后会变成这样
        // {"list":[{"tickets":[{"one":2,"two":3},{"one":3,"two":4}],"one":1,"two":2},{"$ref":"$.list[0].tickets[0]"},{"$ref":"$.list[0].tickets[1]"}]}
    }

解决办法

    /**
     * 禁用 fastjson 的 循环引用检测
     * 使用 SerializerFeature.DisableCircularReferenceDetect
     */
    private void testTransfer3() {
        String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]}]";
        JSONArray array = JSON.parseArray(str);
        // 这里添加
        JSONArray tickets = array.getJSONObject(0).getJSONArray("tickets");
        for (int i = 0; i < tickets.size(); i++) {
            array.add(tickets.get(i));
        }

        // 全局关闭
//        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

        // 该次解析关闭
        // 转为 json 字符串的时候,禁用了 fastjson 的 循环检测引用特性
        String s = array.toJSONString(array, SerializerFeature.DisableCircularReferenceDetect);
//        System.out.println(array.toJSONString());
        System.out.println(s);
    }

说明

由于springboot 默认使用 jackson 处理json 请求,所以需要注意
由于时间问题,这个地方只是发现情况会出现这种问题,至于对象引用会不会出现这种问题,没有进行实验,也没有对fastjson 源码进行解读

posted @ 2021-01-27 16:19  kzcming  阅读(813)  评论(0编辑  收藏  举报