当前位置: 首页 > 后端技术 > Java

FastJson序列化存在“$ref”问题

时间:2023-04-01 16:56:51 Java

使用FastJson序列化对象时,发现json字符串中始终存在“$ref”。具体的例子如下:publicStringbuildRiskQueryLogFastJson(BaseContextbaseContext,Map>riskRejectMap){HashMapdimensionMap=newHashMap<>(baseContext.getDimensionInfoMap());对于(StringuniqueKey:baseContext.getUniqueKeyList()){RiskQueryLogDOriskQueryLogDO=newRiskQueryLogDO();riskQueryLogDO.setQueryType(baseContext.getQueryType());riskQueryLogDO.setRiskCheckId(baseContext.getRiskCheckId());(baseContext.getEventId());riskQueryLogDO.setChannel(baseContext.getChannel());riskQueryLogDO.setOrigin(baseContext.getOrigin());riskQueryLogDO.setUnique键(唯一键);如果(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=newHashMap<>();msgMap.put("数据",riskQueryLogDOList);返回JSON.toJSONString(msgMap);}@TestpublicvoidsendMessageTest(){BaseContextbaseContext=newBaseContext();MapdimensionInfoMap=newHashMap<>();dimensionInfoMap.put(ContextKeyConstant.USER_ID,"110119120");dimensionInfoMap.put(ContextKeyConstant.USER_TYPE,"2");dimensionInfoMap.put(ContextKeyConstant.USER_ID_TYPE,"1");List>contextInfoMapList=newArrayList<>();ListuniqueKeyList=newArrayList<>();for(inti=0;i<100;i++){MapinfoMap=newHashMap<>();infoMap.put(ContextKeyConstant.ACTIVITY_CATEGORY,"2");infoMap.put(ContextKeyConstant.ACTIVITY_TYPE_ID,String.valueOf(newRandom().nextInt(10)));infoMap.put(ContextKeyConstant.ASSUME_TYPE,String.valueOf(newRandom().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。获取代码());baseContext.setRiskCheckId(String.valueOf(newRandom(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=newHashMap<>();MapinfoResultMap=newHashMap<>();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(inti=0;i<30;i++){riskRejectMap.put(String.valueOf(i),infoResultMap);}//riskQueryLogProducer.sendMessage(baseContext,riskRejectMap);System.out.println(riskQueryLogProducer.buildRiskQueryLogFastJson(baseContext,riskRejectMap));结果是这样的:可以看到对于一个对象,第一次出现的时候,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异常,所以循环引用检测保护参考https://juejin.cn/post/684490...https://blog.csdn.net/fly9109。..