【Bug经验分享】由jsonObject-TypeReference引发的序列化问题

发布于:2025-08-14 ⋅ 阅读:(12) ⋅ 点赞:(0)

报错

fastjson.JSONException: syntax error, expect {, actual string

背景

InnerResult<Map<Long, Price>> categoryAttributeRequiredSPMResp = JsonUtil.convertJSONString2Object(res, new TypeReference<InnerResult<Map<Long, Price>>>() { });

在这段代码中会出现反序列化 "异常",转换不了Price对象,在之前的测试中一直都是这种方式使用的,也可以转换为Price对象但是,突然在某一天生产上抛出了异常,定位后发现是在这里出现了类型转换异常,复杂对象序列化为json字符串之后,反序列化的时候异常,明明类型是对的,但是就是转换失败,详细代码如下:

public Map<Long, Price> listPriceByIds(List<Long> productIds) {
    if (CollectionUtils.isEmpty(productIds)) {
        return new HashMap<>();
    }
    String url = spmUrl + "/supplier-product-self-built-product/purchase-price";
    try {
        String res = HttpUtils.postBody(url, "json", JSON.toJSONString(productIds));
        logger.info("获取SPM采购价格,traceId={},请求地址={},请求参数={},响应={}", SwapAreaUtils.getSwapArea().get(Constant.TRACE_KEY), url, JSON.toJSONString(productIds), res);
        InnerResult<Map<Long, Price>> categoryAttributeRequiredSPMResp = JsonUtil.convertJSONString2Object(res, new TypeReference<InnerResult<Map<Long, Price>>>() {
        });
        if (!categoryAttributeRequiredSPMResp.getCode().equals(0)) {
            return new HashMap<>();
        }
        return categoryAttributeRequiredSPMResp.getData();
    } catch (Exception e) {
        logger.error("获取SPM采购价格,traceId={},请求地址={},请求参数={}", SwapAreaUtils.getSwapArea().get(Constant.TRACE_KEY), url, JSON.toJSONString(productIds));
        logger.error("获取SPM采购价格接口失败", e);
        return new HashMap<>();
    }
}
/**
 * 将json串转换为类型为className的对象.
 * 处理如下json:{'field1':1,'field2':'a'}
 *
 * @param <T>        类型参数
 * @param jsonString json字符串
 * @param type       TypeReference<T>
 * @return 对象
 */
public static <T> T convertJSONString2Object(String jsonString, TypeReference<T> type) {
    return JSON.parseObject(jsonString, type);
}

修复

public Map<Long, Price> listPriceByIds(List<Long> productIds) {
    if (CollectionUtils.isEmpty(productIds)) {
        return new HashMap<>();
    }
    String url = spmUrl + "/supplier-product-self-built-product/purchase-price";
    try {
        String res = HttpUtils.postBody(url, "json", JSON.toJSONString(productIds));
        logger.info("获取SPM采购价格,traceId={},请求地址={},请求参数={},响应={}", SwapAreaUtils.getSwapArea().get(Constant.TRACE_KEY), url, JSON.toJSONString(productIds), res);
        InnerResult<JSONObject> innerResult = JsonUtil.convertJSONString2Object(res, new TypeReference<InnerResult<JSONObject>>() {
        });
        if (!innerResult.getCode().equals(0)) {
            return new HashMap<>();
        }
        Map<Long, Price> resultMap = new HashMap<>();

        for (Map.Entry<String, Object> entry : innerResult.getData().entrySet()) {
            Price price = JSON.parseObject(JSON.toJSONString(entry.getValue()), Price.class);

            if (price != null) {
                resultMap.put(Long.valueOf(entry.getKey()), price);
            }
        }
        return resultMap;
    } catch (Exception e) {
        logger.error("获取SPM采购价格,traceId={},请求地址={},请求参数={}", SwapAreaUtils.getSwapArea().get(Constant.TRACE_KEY), url, JSON.toJSONString(productIds));
        logger.error("获取SPM采购价格接口失败", e);
        return new HashMap<>();
    }
}

主要是先将返回值转为 JSONObject 对象,其次取出key,value后自行组装Map这样是稳妥解决了这个类型转换的异常



反思


在定位这个问题的时候,就从来没想过这边会出现问题,因为代码是完全没有动过的,理论上不会有问题,打日志定位后 发现 但是 很鬼畜的事情就是突然发生 类型转换异常,那为什么之前从来没出现过这个问题,怀疑是 alibaba.fastjson 这个包下的TypeReference 序列化 多多少少是有Bug的,不知道是不是版本不稳定引起的--  后面再看看吧

 


网站公告

今日签到

点亮在社区的每一天
去签到