Samples DataBind FastJson循环引用问题

Fastjson full support databind, it‘s simple to use.

Encode

import com.alibaba.fastjson.JSON;

Group group = new Group();
group.setId(0L);
group.setName("admin");

User guestUser = new User();
guestUser.setId(2L);
guestUser.setName("guest");

User rootUser = new User();
rootUser.setId(3L);
rootUser.setName("root");

group.addUser(guestUser);
group.addUser(rootUser);

String jsonString = JSON.toJSONString(group);

System.out.println(jsonString);

Output

{"id":0,"name":"admin","users":[{"id":2,"name":"guest"},{"id":3,"name":"root"}]}

Decode

String jsonString = ...;
Group group = JSON.parseObject(jsonString, Group.class);

Group.java

public class Group {

    private Long       id;
    private String     name;
    private List<User> users = new ArrayList<User>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

        public void addUser(User user) {
            users.add(user);
        }
}

User.java

public class User {

    private Long   id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

https://github.com/alibaba/fastjson/wiki/Samples-DataBind

上周帮同事看一个问题,是想构造一个万能的query对象,这个对象里面包含一个泛型的对象,在spring mvc的controller层想通过RequestBody直接进行转换,spring mvc的代码如下:

Java代码  

  1. @RequestMapping("/testBind")
  2. @ResponseBody
  3. public String testBind(@RequestBody MgQueryCondition<TestBean> queryCondition){
  4. System.out.println(queryCondition);
  5. return "success";
  6. }

Java代码  

  1. import java.io.Serializable;
  2. public class TestBean implements Serializable{
  3. private Integer id;
  4. public Integer getId() {
  5. return id;
  6. }
  7. public void setId(Integer id) {
  8. this.id = id;
  9. }
  10. @Override
  11. public String toString() {
  12. return "TestBean [id=" + id + "]";
  13. }
  14. }

Java代码  

  1. import com.alibaba.fastjson.JSON;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.alibaba.fastjson.TypeReference;
  4. public class MgQueryCondition<T> {
  5. private T model;
  6. private Integer pageNo;
  7. private Integer pageNum;
  8. public T getModel() {
  9. return model;
  10. }
  11. public void setModel(T model) {
  12. this.model = model;
  13. }
  14. public Integer getPageNo() {
  15. return pageNo;
  16. }
  17. public void setPageNo(Integer pageNo) {
  18. this.pageNo = pageNo;
  19. }
  20. public Integer getPageNum() {
  21. return pageNum;
  22. }
  23. public void setPageNum(Integer pageNum) {
  24. this.pageNum = pageNum;
  25. }
  26. @Override
  27. public String toString() {
  28. return "MgQueryCondition [model=" + model + ", pageNo=" + pageNo
  29. + ", pageNum=" + pageNum + "]";
  30. }
  31. }

假设我们去调试的话,发现MgQueryCondition里面的数据类型是JSONObject,如果如果在调用getModel的时候就会发生类型转换问题,后来我看了下fastjson的文档。

针对泛型类型,使用TypeReference进行解析,代码如下:

Java代码  

  1. public static void main(String[] args) {
  2. MgQueryCondition<TestBean> test = new MgQueryCondition<TestBean>();
  3. TestBean testBean = new TestBean();
  4. testBean.setId(1);
  5. test.setModel(testBean);
  6. test.setPageNo(1);
  7. test.setPageNum(1);
  8. System.out.println(JSONObject.toJSONString(test));
  9. String json = "{\"model\":{\"id\":1},\"pageNo\":1,\"pageNum\":1}";
  10. <strong>MgQueryCondition<TestBean> clazz = JSON.parseObject(json,
  11. new TypeReference<MgQueryCondition<TestBean>>(){});</strong>
  12. System.out.println(clazz.getModel().getClass());
  13. }

这样我们就无法使用@RequestBody了,所以应该使用最基本的kv结构的进行传参。

FastJson循环引用问题

什么是循环引用和重复引用

重复引用:一个对象中的多个属性同时引用同一个对象 
例如:

        Object obj=new Object();
        Map<String,Object> map=new HashMap<>();
        map.put("1", obj);
        map.put("2", obj);//引用了同一个对象
        System.out.println(JSON.toJSONString(map));
  • 1
  • 2
  • 3
  • 4
  • 5

循环引用:对象的属性之间存在相互引用导致循环,会引起StackOverFlow异常 
例如:

        Map<String,Object> map1=new HashMap<>();
        Map<String,Object> map2=new HashMap<>();
        map1.put("1",map2);//map1引用了map2
        map2.put("1",map1);//map2又引用了map1,导致循环引用
        System.out.println(JSON.toJSONString(map1));
  • 1
  • 2
  • 3
  • 4
  • 5

FastJson如何解决循环引用/重复引用

fastjson支持循环引用/重复引用,并且是缺省打开的。 
* 第一个例子序列化后输出结果为:{"1":{},"2":{"$ref":"$.1"}} 
第一个对象正常序列化,第二个对象则用引用表示 
* 第二个列子序列化后输出结果为:{"1":{"1":{"$ref":".."}}}

根据fastJson的语法:

语法 描述
{“$ref”:”\$”} 引用根对象
{“$ref”:”@”} 引用自己
{“$ref”:”..”} 引用父对象
{“$ref”:”../..”} 引用父对象的父对象
{“$ref”:”\$.members[0].reportTo”} 基于路径的引用

可以得出,”$.1”表示引用根对象(map)的第一个元素(obj),”..”表示引用父对象(map1).

关闭循环引用/重复引用

fastjson默认对json序列化的时候进行循环引用的检测,从而避免了出现StackOverFlow异常。当序列化后的JSON传输到浏览器或者其他语言中,这些json解析器不支持循环引用,从而导致数据丢失。你可以关闭fastjson的循环引用检测。 
全局配置关闭

  JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

非全局关闭

  JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);

处理StackOverFlowException

关闭循环引用检测功能后,在序列化的时候会出现StackOverFlow异常,这时需要用户处理好属性之间是否有循环引用的情况出现: 
可以在字段或者getter方法上使用@JSONField(serialize=false)注解来设置某些域不进行序列化,从而避免循环引用的情况发生。

http://blog.csdn.net/helloxiaoyueyue/article/details/51173168

时间: 2024-10-12 15:44:34

Samples DataBind FastJson循环引用问题的相关文章

JSON工具学习记录--FastJSON循环引用问题

JSON工具学习记录–FastJSON循环引用问题 标签(空格分隔): fastjson 最近基于他人项目做二次开发,遇到了循环引用的问题,简单来说A引用了B,B引用了C,C引用了A,那么转换json就会无休止的转换下去. 更复杂的情况,A中引用了B,B中引用了一个A的集合,比如广告引用了广告类型,广告类型里面又有该类型下的所属广告. 1.构造情景 这种又叫做双向引用,个人感觉这种设计本身就不是很合理,当然还要看具体使用场景了. 广告类: /** * @author Niu Li * @date

从循环引用到hibernate的游离化

问题描述: 列表页面,50多条数据只显示3条,其他的也显示出来了,不过全部都是空白,差点哭晕在厕所 然后debug断点进去看,发现好多的json数据长这个样子的 "dept":{"$ref":"$[0].dept" (这里给的是类似这样的字符串) "$ref":"$"} 引用根对象 {"$ref":"@"} 引用自己 {"$ref":".

JPA一对多循环引用的解决

说是解决,其实不是很完美的解决的,写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的,能否知道一二. 下面说说出现问题: 问题是这样的,当我查询一个一对多的实体的时候,工具直接就爆了,差不多我就猜到是哪里死循环了,最后等了好久,查看原因,果然是堆溢出,再然后是jsckson的错误.那么必然是序列化的问题了. 这是jackson的错误: at java.security.AccessController.doPrivileged(Native Method) at java.net.URLC

iOS Block循环引用

前言 本篇文章精讲iOS开发中使用Block时一定要注意内存管理问题,很容易造成循环引用.本篇文章的目标是帮助大家快速掌握使用block的技巧. 我相信大家都觉得使用block给开发带来了多大的便利,但是有很多开发者对block内存管理掌握得不够好,导致经常出现循环引用的问题.对于新手来说,出现循环引用时,是很难去查找的,因此通过Leaks不一定能检测出来,更重要的还是要靠自己的分析来推断出来. 声景一:Controller之间block传值 现在,我们声明两个控制器类,一个叫ViewContr

解决Block弱引用可能造成的循环引用

1.__weak typeof(self) myself = self; 2.__weak RecommendViewController *recommendVC = self; 以上两种写法是一种效果 typeof(self) 是获取到self的类型,这样定义出的weakSelf就是和self一个类型的, 加上__weak是建立一个若引用,整句就是给self定义了一个若引用性质的替身;这个一般用在使用block时会用到,因为block会copy它内部的变量,可能会造成引用循环,使用__wea

智能指针的模拟实现shared_ptr 循环引用 定置删除器

auto_ptr与scoped_ptr的实现见本人的上篇博客. 三.shared_ptr shared_ptr的实现原理是通过引用计数来实现,只有当引用计数为1时才释放空间,否则只需将引用计数减1.拷贝和赋值将引用计数加1,具体代码如下: template <typename T> class SharedPtr { public: SharedPtr(); SharedPtr(T* ptr); SharedPtr(const SharedPtr<T>& ap); ~Sha

【IOS学习基础】weak和strong、懒加载、循环引用

一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成引用计数加1:而strong则相当于OC中规定retain,它会造成引用计数加1”. ARC的原理:只要还有一个变量指向对象,对象就会保持在内存中.当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放.这条规则对于实例变量.synthesize属性.局部变量都是适用的 strong指针能够保

iOS容易造成循环引用的三种场景NSTimer以及对应的使用方法(一)

NSTimer A timer provides a way to perform a delayed action or a periodic action. The timer waits until a certain time interval has elapsed and then fires, sending a specified message to a specified object(timer就是一个能在从现在开始的未来的某一个时刻又或者周期性的执行我们指定的方法的对象)

block使用小结、在arc中使用block、如何防止循环引用

引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题 : [小测试]你真的知道blocks在Objective-C中是怎么工作的吗?,发现竟然做错了几道, 才知道自己想当然的理解是错误的,所以抽时间学习了下,并且通过一些测试代码进行测试,产生这篇博客. Block简介(copy一段) Block作为C语言的扩展,并不是高新技术,和其他语言的闭包或lambda表达式是一回事.需要注意的是由于Objective-C在iOS中不支