There is a "$ref" problem with FastJson serialization

Posted by adamhhh1 on Fri, 21 Jan 2022 11:55:36 +0100

When serializing objects with FastJson, it is found that "$ref" always exists in the json string. The specific examples are as follows:

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));
    }

The result is:

It can be seen that for an object, fastjason serialization works normally when it appears for the first time, but when it appears repeatedly, it will be serialized and become a reference to the object It is conceivable that there must be some special logic in fastjason. The reason for the problem is that fastjason has a circular / repeated reference detection feature, which is enabled by default.
After the entity is converted into a json string, the word $ref appears. This is because when the same object appears in the transmitted data, fastjson turns on reference detection by default, and writes the same object in the form of reference, which is represented by "$ref".

quotedescribe
"$ref":".."Upper level
"$ref":"@"Current object, that is, self reference
"$ref":"$"Root object
"$ref":"$.children.0"Path based reference, equivalent to root getChildren(). get(0)

To solve this problem, it is very simple. You just need to add the original menujson Tojsonstring() is changed to the following code:

JSON.toJSONString(msgMap, SerializerFeature.DisableCircularReferenceDetect);

If you want to turn this feature off globally:

JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

Why does fastjason want this feature?
fastjson detects circular references during JSON serialization by default, thus avoiding StackOverFlow exceptions. When the serialized JSON is transferred to the browser or other languages, these JSON parsers do not support circular references, resulting in data loss.
Question: since the browser does not support this function in many scenarios, why set this function to be enabled by default?
The reason is that if there is a circular reference, SOF exceptions are likely to occur. Therefore, the protection of circular reference detection is designed

reference
https://juejin.cn/post/684490...
https://blog.csdn.net/fly9109...

Topics: Java