关于Caused by: com.alibaba.fastjson.JSONException: syntax error, expect }, actual ,

Fastjson升级问题

目录

Fastjson升级问题

问题背景

问题现象

问题堆栈信息

问题解决之路(思考方向)

复现问题

问题原因

问题解决

参考博客

问题背景

Fastjson版本由于存在安全漏洞,公司要求各个部门对所属应用中存在低于1.2.83版本的fastjson升级应用升级到1.2.83,即低版本fastjson升级到高版本。

问题现象


Caused by: com.alibaba.fastjson.JSONException: syntax error, expect }, actual ,

问题堆栈信息

Method: checkLogin,

exception: com.alibaba.fastjson.JSONException: syntax error, expect }, actual ,, dubbo version: 2.4.7, current host: 172.21.21.38
com.alibaba.fastjson.JSONException: syntax error, expect }, actual ,
at com.alibaba.fastjson.util.TypeUtils.castToJavaBean(TypeUtils.java:1569)
at com.alibaba.fastjson.util.TypeUtils.cast(TypeUtils.java:1127)
at com.alibaba.fastjson.util.TypeUtils.castToJavaBean(TypeUtils.java:1069)
at com.alibaba.fastjson.JSONArray.getObject(JSONArray.java:273)
at com.yao.passport.util.CommonUtil.toUserInfo(CommonUtil.java:10)
atjava.lang.Thread.run(Thread.java:745) Caused by: com.alibaba.fastjson.JSONException: syntax error, expect }, actual , at com.alibaba.fastjson.parser.DefaultJSONParser.accept(DefaultJSONParser.java:1532) at com.alibaba.fastjson.parser.deserializer.AbstractDateDeserializer.deserialze(AbstractDateDeserializer.java:161) at com.alibaba.fastjson.parser.deserializer.AbstractDateDeserializer.deserialze(AbstractDateDeserializer.java:16) at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:88) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField(JavaBeanDeserializer.java:1278) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:893) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseRest(JavaBeanDeserializer.java:1624) at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_3_EcuserCustomer.deserialze(Unknown Source) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:287) at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:88) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.createInstance(JavaBeanDeserializer.java:1413) at com.alibaba.fastjson.util.TypeUtils.castToJavaBean(TypeUtils.java:1567) ... 75 common frames omitted

问题解决之路(思考方向)

复现问题

  1. 第一反应是从redis获取到字符串不满足fastjson格式

但是如果不是json格式,那么早就应该报问题了。

然后加日志,输出从redis中的取出的字符串,发现字符串格式正常且符合json格式:

[{"userInfo":"","jun":"","jum":"","nickName":"xxxxxx","openUserFlag":"open","userName":"xxxx","userId":"111111","yzToken":"","expiredTime":"1661338531800","token":"xxxxxx","moniPharmacistId":"","result":0,"userLeverId":1,"loginTime":"1661338531800","gltoken":"","jud":"","member":null,"userIp":"222.191.226.242","customer":{"registerIP":"","companyName":"","channel":"","source":10,"type":0,"password":"xxxxxx","province":"0","id":"xxxxxxx","modifyDate":null,"nickName":"13270162613","telephone":"","version":"","userLevelStartTime":null,"isOldUser":0,"realPassword":"","district":"","name":"","partnerType":0,"userType":"","enterCount":0,"requestTag":"","cardNumber":"","isBindMobileToWexin":0,"loginMobile":"xxxxxx","status":1,"income":0,"ipaddress":"127.0.0.1","gender":1,"city":"","openId":null,"ecUId":0,"loginEmail":"","isDeleted":0,"cellphone":"","promoCode":"","popType":0,"email":"","userLevelEndTime":null,"userLevelId":1,"createDate":{"date":21,"hours":11,"seconds":17,"month":4,"timezoneOffset":-480,"year":120,"minutes":59,"time":1590033557000,"day":4},"birthDay":null,"address":"","salt":"L1TIwT","partnerName":"","userscore":0,"baoGangUser":false,"ecUserId":xxxxxx,"userId":"","moniPharmacistId":"","lastLoginTime":null,"partnerId":""}}]

  2 . 本地复现问题

本地使用junit来模拟“将redis 存入用户数据,然后调用出错的代码取数据”这个流程,结果正常,正常,正常!结果怎么会正常呢?

开始怀疑是两个字符串不一样,对比发现字符串中createDate不一样。

json字符串中异常的createDate,如下:

 

正常的createDate,如下:

 

3. 怀疑json包混合使用导致(createDate怎么会是这种格式?)

 

createDate在类中定义的是java.util.Date类型,json成字符串怎么会是这种格式呢?

什么操作会导致它变成这样了(它到底经历了什么)?

开始怀疑net.sf.json包和fastjson混用导致的,经过验证发现,果然这种格式正是net.sf.json包中的处理方式(心里一万头羊驼奔驰)。

  1. 问题原因

net.sf.json包中的JSONArray和JSONObject会将java.util.Date类型的createDate格式化为json字符串,即

"createDate":{"date":31,"hours":18,"seconds":14,"month":4,"timezoneOffset":-480,"year":121,"minutes":53,"time":1622458394000,"day":1},

而我们实际需要的时long类型的值,或者指定日期格式的字符串。

总的来说:

项目中net.sf.json包和alibaba 混合使用,使用net.sf.json包中的类将对象格式化后存入到Redis,解析redis中的字符串却使用的fastjson。

那么怎么混用的呢?神奇的操作(听我说,谢谢你!!!)。

在一段业务中,存入redis中的用户信息使用net.sf.json包格式化为字符串的,如下:

public void setUserInfoToRedis(UserInfo userInfo, EcuserCustomer customer, int type) {

//此处的JSONArray是net.sf.json.JSONArray而不是fastjson中的

        String value = String.valueOf(JSONArray.fromObject(userInfo));

        if (type == 1) {

            String key = customer.getId() + USERINFO;

            int ttl = PassportApolloConfigUtil.getConfigIntVal("userinfoweek_expire");

            RedisUtils.set(key, value, Long.valueOf(ttl));

        } else {

            set(customer.getId(), USERINFO, value);

        }

 }


而从redis中取出字符串后,使用alibaba的fastjson解析的,如下:

 public static UserInfo toUserInfo(String value){

        return  com.alibaba.fastjson.JSONArray.parseArray(value).getObject(0,UserInfo.class);

    }

        目前看低版本支持net.sf.json和alibaba混用,但是高版本fastjson进行了优化,不再兼容,所以升级导致报错。

问题解决

通过兜底逻辑兼容解析json字符串。

(1)针对解析报错的字符串,我们就认为是net.sf.JSON包处理的,所以我们使用net.sf包下的解析。

(2)针对可以正常解析的的json字符串,我们还是使用alibaba fastjson来解析。

处理代码如下:

public static UserInfo toUserInfo(String value) {
    log.info("从redis中获取的用户信息字符串userInfoStr={}", value);
    UserInfo userInfo = null;
    try {
        userInfo = com.alibaba.fastjson.JSONArray.parseArray(value).getObject(0, UserInfo.class);
    } catch (Exception e) {
        log.error("使用fast json解析字符串异常,异常信息error={},尝试使用net.sf.json解析字符串。", e.getMessage());
        JSONArray jsonArray = JSONArray.fromObject(value);
        JSONObject jsonObject = (JSONObject) jsonArray.get(0);
        userInfo = (UserInfo) JSONObject.toBean(jsonObject, UserInfo.class);
    }
    return userInfo;
}

参考博客

1.时间Date格式转换为json后出现的问题处理_向上吧! 少年的博客-CSDN博客_date json

2.java中使用net.sf.json对json进行解析_shanliangliuxing的博客-CSDN博客

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
com.alibaba.fastjson.JSONException 是一个 JSON 解析/生成异常类,通常是由 fastjson 库在处理 JSON 字符串时发生错误导致的。 出现 "com.alibaba.fastjson.JSONException: write JavaBean error" 错误一般是由以下原因引起的: 1. JavaBean 对象和 JSON 字符串之间的属性不匹配。例如,JavaBean 对象缺少某些属性或 JSON 字符串包含了多余的属性,导致无法正确地将 JSON 字符串转换成 JavaBean 对象,或者无法将 JavaBean 对象转换成相应的 JSON 字符串。 解决方法:检查 JavaBean 对象和 JSON 字符串之间的属性是否一一对应并正确设置。 2. JavaBean 对象的属性和 JSON 字符串的属性类型不匹配。例如,JavaBean 对象中的属性是长整型,但是 JSON 字符串中对应的属性是字符串类型,导致类型转换错误。 解决方法:确保 JavaBean 对象的属性类型和 JSON 字符串中对应的属性类型一致。 3. JavaBean 对象中存在循环引用。即 JavaBean 对象的属性中包含了对自身的引用,导致 fastjson 无法正确处理。 解决方法:避免在 JavaBean 对象中出现循环引用,可以通过在 JavaBean 对象中使用 @JSONField(serialize=false) 注解来标记该属性不被序列化。 总之,"com.alibaba.fastjson.JSONException: write JavaBean error" 错误通常是由于 fastjson 在处理 JSON 字符串和 JavaBean 对象之间的转换时出现了问题。要解决这个错误,需要检查 JavaBean 对象和 JSON 字符串之间的属性是否匹配,并且确保属性类型一致。另外,要避免在 JavaBean 对象中出现循环引用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值