riskRejectMap) {List riskQueryLogDOList = new ArrayList ();。FastJson 序列化出现"$ref"问题。" />

FastJson 序列化出现"$ref"问题

在用FastJson对对象进行序列化时,发现出来的json字符串中始终存在"$ref",具体示例如下:

public String buildRiskQueryLogFastJson(BaseContext baseContext, Map> riskRejectMap) { List riskQueryLogDOList = new ArrayList<>(); HashMap dimensionMap = new HashMap<>(baseContext.getDimensionInfoMap()); for (String uniqueKey : baseContext.getUniqueKeyList()) { RiskQueryLogDO riskQueryLogDO = new RiskQueryLogDO(); riskQueryLogDO.setQueryType(baseContext.getQueryType()); riskQueryLogDO.setRiskCheckId(baseContext.getRiskCheckId()); riskQueryLogDO.setBizLine(baseContext.getBizLine()); riskQueryLogDO.setEventId(baseContext.getEventId()); riskQueryLogDO.setChannel(baseContext.getChannel()); riskQueryLogDO.setOrigin(baseContext.getOrigin()); riskQueryLogDO.setUniqueKey(uniqueKey); if (riskRejectMap.containsKey(uniqueKey)) { riskQueryLogDO.setRiskResult(DecisionCodeEnum.getFromName(riskRejectMap.get(uniqueKey).get(ContextKeyConstant.RISK_RESULT)).getCode()); } else { riskQueryLogDO.setRiskResult(DecisionCodeEnum.PASS.getCode()); } riskQueryLogDO.setDimensionData(dimensionMap); riskQueryLogDOList.add(riskQueryLogDO); } Map> msgMap = new HashMap<>(); msgMap.put("data", riskQueryLogDOList); return JSON.toJSONString(msgMap); }

@Test public void sendMessageTest(){BaseContext baseContext = new BaseContext(); Map dimensionInfoMap = new HashMap<>(); dimensionInfoMap.put(ContextKeyConstant.USER_ID, "110119120"); dimensionInfoMap.put(ContextKeyConstant.USER_TYPE, "2"); dimensionInfoMap.put(ContextKeyConstant.USER_ID_TYPE, "1"); List contextInfoMapList = new ArrayList<>(); List uniqueKeyList = new ArrayList<>(); for (int i = 0; i < 100; i++) { Map infoMap = new HashMap<>(); infoMap.put(ContextKeyConstant.ACTIVITY_CATEGORY, "2"); infoMap.put(ContextKeyConstant.ACTIVITY_TYPE_ID, String.valueOf(new Random().nextInt(10))); infoMap.put(ContextKeyConstant.ASSUME_TYPE, String.valueOf(new Random().nextInt(2))); infoMap.put(ContextKeyConstant.ACTIVITY_ID, String.valueOf(i)); infoMap.put(ContextKeyConstant.APPLY_ID, String.valueOf(i)); infoMap.put(ContextKeyConstant.UNIQUE_KEY, String.valueOf(i)); contextInfoMapList.add(infoMap); uniqueKeyList.add(String.valueOf(i)); } baseContext.setQueryType(QueryTypeEnum.BATCH_AGGREGATION.getCode()); baseContext.setRiskCheckId(String.valueOf(new Random(100).nextInt())); baseContext.setBizLine(1); baseContext.setEventId(1); baseContext.setChannel(1); baseContext.setOrigin(1); baseContext.setDimensionInfoMap(dimensionInfoMap); baseContext.setContextInfoMapList(contextInfoMapList); baseContext.setUniqueKeyList(uniqueKeyList); Map> riskRejectMap = new HashMap<>(); Map infoResultMap = new HashMap<>(); infoResultMap.put(ContextKeyConstant.RISK_RESULT, DecisionCodeEnum.REJECT.getName()); infoResultMap.put(ContextKeyConstant.ACTIVITY_CATEGORY, "2"); infoResultMap.put(ContextKeyConstant.ACTIVITY_TYPE_ID, "1"); infoResultMap.put(ContextKeyConstant.ACTIVITY_ID, "1"); infoResultMap.put(ContextKeyConstant.APPLY_ID, "1"); infoResultMap.put(ContextKeyConstant.ASSUME_TYPE, "1"); for (int i = 0; i < 30; i++) { riskRejectMap.put(String.valueOf(i), infoResultMap); } //riskQueryLogProducer.sendMessage(baseContext, riskRejectMap); System.out.println(riskQueryLogProducer.buildRiskQueryLogFastJson(baseContext, riskRejectMap)); }

结果是这样的:
FastJson 序列化出现"$ref"问题
文章图片

可以看到,对于一个对象,当其首次出现时,FastJson的序列化是正常工作的,但是当其重复出现时,就会序列化实现,变为对象的引用.可以想到,这一定是FastJson内部存在一些特殊逻辑,问题产生的原因在于FastJson存在循环/重复引用检测特性,并且该特性是缺省开启的。
实体转化为json字符串后出现了$ref字样的东西,这是因为在传输的数据中出现相同的对象时,fastjson默认开启引用检测将相同的对象写成引用的形式,引用是通过"$ref"来表示的。
引用 描述
"$ref":".." 上一级
"$ref":"@" 当前对象,也就是自引用
"$ref":"$" 根对象
"$ref":"$.children.0" 基于路径的引用,相当于 root.getChildren().get(0)
想要解决这个问题,非常简单,只需要将原来的menujson.toJSONString()改为如下代码:
JSON.toJSONString(msgMap, SerializerFeature.DisableCircularReferenceDetect);

如果想要全局关闭该功能:
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

FastJson要这个特性干吗用?
fastjson默认对json序列化的时候进行循环引用的检测,从而避免了出现StackOverFlow异常。当序列化后的JSON传输到浏览器或者其他语言中,这些json解析器不支持循环引用,从而导致数据丢失。
疑问: 既然在很多场景下浏览器并不支持该功能,那么为甚么还要把这个功能设置为缺省开启呢?
原因在于,如果存在循环引用,很有可能会出现SOF异常,因此设计了循环引用检测的保护
【FastJson 序列化出现"$ref"问题】reference
https://juejin.cn/post/684490...
https://blog.csdn.net/fly9109...

    推荐阅读