在用 FastJson 对对象进行序列化时, 发现进去的 json 字符串中始终存在 ”$ref”, 具体示例如下:
public String buildRiskQueryLogFastJson(BaseContext baseContext, Map<String, Map<String, String>> riskRejectMap) {List<RiskQueryLogDO> riskQueryLogDOList = new ArrayList<>();
HashMap<String, String> 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<String, List<RiskQueryLogDO>> msgMap = new HashMap<>();
msgMap.put("data", riskQueryLogDOList);
return JSON.toJSONString(msgMap);
}
@Test
public void sendMessageTest(){BaseContext baseContext = new BaseContext();
Map<String, String> dimensionInfoMap = new HashMap<>();
dimensionInfoMap.put(ContextKeyConstant.USER_ID, "110119120");
dimensionInfoMap.put(ContextKeyConstant.USER_TYPE, "2");
dimensionInfoMap.put(ContextKeyConstant.USER_ID_TYPE, "1");
List<Map<String, String>> contextInfoMapList = new ArrayList<>();
List<String> uniqueKeyList = new ArrayList<>();
for (int i = 0; i < 100; i++) {Map<String, String> 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<String, Map<String, String>> riskRejectMap = new HashMap<>();
Map<String, String> 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 的序列化是失常工作的, 然而当其反复呈现时, 就会序列化实现, 变为对象的援用. 能够想到, 这肯定是 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 异样, 因而设计了循环援用检测的爱护
reference
https://juejin.cn/post/684490…
https://blog.csdn.net/fly9109…