关于FastJson出现对象引用问题的解决方案

这里首先说一下后台返回的json格式

总结了一下,大概就是两种:

对象 -----{"key"  , "value"} 对象类型

集合-----{"key"  , "value"} ,{"key"  , "value"} ]数组/集合类型 

注意:在json转换中 对象即Map , Map 即对象 ; 换言而止 , Map 和对象类型转换出来的json字符串格式是一样的;

下面是一个demo演示一下

    @Test
    public void MapToJson(){
        //map类型
        Map map = new HashMap();
        map.put("username" , "东方月初");
        map.put("password" , "123456");
        System.out.println(JSON.toJSONString(map));

        //对象类型
        User user = new User();
        user.setUsername("东方月初");
        user.setPassword("123456");
        System.out.println(JSON.toJSONString(user));
    }

打印结果截图

当前除了这两种 , 还有以各种复杂的格式就是 对象中包含 集合 , 集合中包含对象的混合类型json串, 原理大概差不多 ,这里就不多做解释


接下来进入正题

在有时候,业务逻辑复杂的时候 , 返回的json字符串中可能会出现对象引用的问题, 什么是对象引用呢, 这里简单的做一下演示

首先模拟一个json对象引用的情况

 @Test
    public void jsonTest(){
        //对象类型
        User user = new User();
        user.setUsername("东方月初");
        user.setPassword("123456");

        List<User> userList = new ArrayList<User>();
        //存储两个相同的对象
        userList.add(user);
        userList.add(user);
        System.out.println(JSON.toJSONString(userList));//打印结果[{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]
        /*
            [{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]
            {"$ref":"$[0]"}
            $ref -----链接地址
            $[0] -----list集合的索引值
            这里因为list集合中的第二个对象的key 和value 域第一个对象的key和value完全一样 , 所以会出现这种情况
            可以把他理解为系统简写了第二个对象

            在业务逻辑比较复杂的情况下,后台有时候会出现这种对象引用的问题 , 可是这个json串传送给前端页面后 , 前端页面不会识别 ,

         */

解决方案

关闭toJSONString转换json过程中的循环引用

这里是toJSONString的一个构造方法

public static String toJSONString(Object object, SerializerFeature... features) {
    return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}

参数2 SerializerFeature 中有一个属性DisableCircularReferenceDetect

作用为关闭循环应用 , 默认情况下为开启

修改上面代码中的参数

 System.out.println(JSON.toJSONString(userList , SerializerFeature.DisableCircularReferenceDetect));

打印结果如下:

[{“password”:“123456”,“username”:“东方月初”},{“password”:“123456”,“username”:“东方月初”}]

关闭循环应用有一个缺点就是 , 在更复杂的json情况加 , 比如

 @Test
    public void jsonTest(){
        //对象类型
        User userA = new User();
        userA.setUsername("东方月初");
        userA.setPassword("123456");

        User userB = new User();
        userB.setUsername("涂山红红");
        userB.setPassword("123456");

        Role role = new Role();
        //role中添加user对象
        role.setRoleName("盟主");
        role.getUserList().add(userA);
        role.getUserList().add(userB);

        userA.getRoleList().add(role);

        //解析user对象的时候 , user对象中包含List<Role> 集合 , 解析role对象的时候 , role对象中有List<User> 集合 , 会陷入死循环状态
        System.out.println(JSON.toJSONString(userA , SerializerFeature.DisableCircularReferenceDetect));

在转换userA的时候 , 由于userA中包含了role , role 中包含了user 这种情况 , 在解析的时候会出现死循环的情况 , 造成堆栈溢出 错误

以上代码运行结果

java.lang.StackOverflowError

at com.alibaba.fastjson.serializer.SerializeWriter.writeFieldValueStringWithDoubleQuoteCheck(SerializeWriter.java:1885)

at com.alibaba.fastjson.serializer.ASMSerializer_1_User.writeDirectNonContext(Unknown Source)

at com.alibaba.fastjson.serializer.ASMSerializer_2_Role.writeDirectNonContext(Unknown Source)

at com.alibaba.fastjson.serializer.ASMSerializer_1_User.writeDirectNonContext(Unknown Source)

解决方案:

在toJSONString的参数中 , 可以传入一个filter过滤器SimplePropertyPreFilter

SimplePropertyPreFilter 写在这个过滤器中的属性都会被解析

SimplePropertyPreFilter filter = new SimplePropertyPreFilter(
        "username","password" , "roleList" , "roleName" );//会解析写入的属性名称
//解析user对象的时候 , user对象中包含List<Role> 集合 , 解析role对象的时候 , role对象中有List<User> 集合 , 会陷入死循环状态
System.out.println(JSON.toJSONString(userA ,filter , SerializerFeature.DisableCircularReferenceDetect));//[{"password":"123456","username":"东方月初"},{"$ref":"$[0]"}]

被过滤的字段就会不显示 , 如果非要全部显示的话 , 介意修改属性名 , 让属性名布绒服

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值