报错
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的,不知道是不是版本不稳定引起的-- 后面再看看吧