fastjson序列化参数丢失

问题现象:

在调用mq去发送短信时,使用了一个jsonString对象去传递参数。发现消费方接收到的jsonString解析出来之后,只有第一个对象的参数有值,后序的参数中出现了$ref。模拟入参场景类似如下

HashMap<String, String> map = Maps.newHashMap();
map.put("mobile", "111111");
List<Object> list = Lists.newArrayList();
list.add(new SmsDTO("内容1", map));
list.add(new SmsDTO("内容2", map));
list.add(new SmsDTO("内容3", map));
list.add(new SmsDTO("内容4", map));
String jsonString = JSON.toJSONString(list);
//调用消息发送方
msg.send(jsonString);

在该场景下,list序列化之后的字符串出现了$ref,具体如下

从上图可以看出,除了第一条数据的参数是正常的,后续的params都出现了$ref。

原因:

其实这个是fastjson的一个机制,当发现需要序列化的对象中有重复的对象,会使用对象的引用来表示。这个是fastjson为了避免出现json序列化的循环引用的一个特性。

// 循环引用的特殊情况,自引用  
Map<String,Object> map = new HashMap<>();  
map.put("map",map);  
//  
// map1引用了map2,而map2又引用map1,导致循环引用  
Map<String,Object> map1 = new HashMap<>();  
Map<String,Object> map2 = new HashMap<>();  
map1.put("map",map2);  
map2.put("map",map1);  

如果碰到以上情况,就会出现内循环,导致出现StackOverFlow异常。作为一个公共组件,fastjson必须保障自身的安全性,所以这些就需要我们从自身代码进行出发改造。

解决办法:

由于循环引用是默认开启的,所以最简单的就是关闭这个特性

JSON.toJSONString(list, SerializerFeature.DisableCircularReferenceDetect);

或者是全局关闭,以springboot为例,通过自定义converter来解决

public class FastJsonHttpMessageConverterEx extends FastJsonHttpMessageConverter{
    public FastJsonHttpMessageConverterEx(){
        //在这里配置fastjson特性(全局设置的)
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
    //关闭循环引用   
    fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);     
        this.setFastJsonConfig(fastJsonConfig);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return super.supports(clazz);
    }
}

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
    .....
    @Bean
    public FastJsonHttpMessageConverterEx fastJsonHttpMessageConverterEx(){
        return new FastJsonHttpMessageConverterEx();
    }
}

以上的方法处理后,都无法避免循环引用的问题。回到原因上,fastjson的这个特性的目的其实就是对于相同对象的一个特殊处理。所以最好的解决办法就是传入不同的对象,彻底避免这个问题。

List<Object> list = new ArrayList<>();
Object obj = new Object();
list.add(obj);
// 创建新的对象
Object newObj = new Object();
// 使用org.springframework.beans.BeansUtils复制属性值
BeansUtils.copyProperties(obj, newObj);
list.add(newObj);

使用对象拷贝的方式避免,是遵守fastjson安全机制的最佳处理方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古柏树下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值