美文网首页
fastjson循环依赖

fastjson循环依赖

作者: 李昂的数字之旅 | 来源:发表于2018-06-10 20:55 被阅读0次

举个例子

HashMap map = new HashMap();
map.put("foo", map);
System.out.println(map);

输出是:{foo=(this Map)},this Map代表map自己引用自己。
如果用fastjson序列换成json会怎么样呢?
fastjson处理json序列化的方法都放在JSON类中,主要有3个方法:

  • toJSON()
  • toJSONString()
  • toJSONByteds()

toJSON()

HashMap map = new HashMap();
map.put("foo", map);
System.out.println(JSON.toJSON(map));

汇报异常Exception in thread "main" java.lang.StackOverflowError,原因跟toJSON实现方式有关

JSONObject json = new JSONObject(innerMap);

for (Map.Entry<Object, Object> entry : map.entrySet()) {
    Object key = entry.getKey();
    String jsonKey = TypeUtils.castToString(key);
    Object jsonValue = toJSON(entry.getValue());//<--这里
    json.put(jsonKey, jsonValue);
}

可以看到对Map的value还会调用toJSON方法,造成了死循环,且对value处理前任何配置都没生效,所以toJSON方法对循环引用无解。

尝试一下toJSONString和toJSONBytes方法

HashMap map = new HashMap();
map.put("foo", map);
System.out.println(JSON.toJSONString(map));
System.out.println(new String(JSON.toJSONBytes(map)));

输出:{"foo":{"$ref":"@"}},跟直接print输出一致。这两个方法会依据配置SerializerFeature.DisableCircularReferenceDetect来控制是否开启重复引用检查,在处理value时判断上下文中是否已经存在对象。如果开启配置,且上下文中value对象已存在则用引用形式表示。

//JavaBeanSerializer.class
public boolean writeReference(JSONSerializer serializer, Object object, int fieldFeatures) {
    SerialContext context = serializer.context;
    int mask = SerializerFeature.DisableCircularReferenceDetect.mask;
    if (context == null || (context.features & mask) != 0 || (fieldFeatures & mask) != 0) {//<--这里
        return false;
    }

    if (serializer.references != null && serializer.references.containsKey(object)) {
        serializer.writeReference(object);
        return true;
    } else {
        return false;
    }
}

不同层级的引用会以不同的符号代替,具体可以参考JSONSerializer.writeReference()方法

相关文章

网友评论

      本文标题:fastjson循环依赖

      本文链接:https://www.haomeiwen.com/subject/psyqeftx.html