zoukankan      html  css  js  c++  java
  • fastjson序列化出现StackOverflowError

    今天在一个web项目里开发功能,记录日志用到了fastjson的序列化,把类型为RetreatRecord的数据对象序列化后打印出来。结果出现StackOverflowError。先贴出来异常堆栈:

    Exception in thread "main" java.lang.StackOverflowError
    	at com.alibaba.fastjson.serializer.JSONSerializer.getContext(JSONSerializer.java:109)
    	at com.alibaba.fastjson.serializer.JavaBeanSerializer.writeReference(JavaBeanSerializer.java:251)
    	at Serializer_1.write1(Unknown Source)
    	at Serializer_1.write(Unknown Source)
    	at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:390)
    	//下面3行堆栈重复300多次
    	at Serializer_1.write1(Unknown Source)
    	at Serializer_1.write(Unknown Source)
    	at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:390)

    经排查原因,发现派生类RetreatRecord继承自DataEntity,DataEntity里有一个User currentUser字段。User也派生自DataEntity。currentUser的get方法如下:

        public User getCurrentUser() {
            if(null==currentUser){
                currentUser=new User();
            }
            return currentUser;
        }

    问题就出现在了currentUser为null时给其初始化的这句上。

    debug程序可见,fastjson包里JSONSerializer.java的如下方法被死循环执行,直到堆栈溢出。

    // D:workspacem3comalibabafastjson1.2.6fastjson-1.2.6-sources.jar!comalibabafastjsonserializerJSONSerializer.java
    
    public final void writeWithFieldName(Object object, Object fieldName, Type fieldType, int fieldFeatures) {
        try {
            if (object == null) {
                out.writeNull();
                return;
            }
    
            Class<?> clazz = object.getClass();
    
            ObjectSerializer writer = getObjectWriter(clazz);
    
            writer.write(this, object, fieldName, fieldType, fieldFeatures);
        } catch (IOException e) {
            throw new JSONException(e.getMessage(), e);
        }
    }

    分析:我们知道fastjson是基于流写入的。不难看出,在调用getCurrentUser时,因为currentUser是null,所以要给currentUser初始化,这时fastjson又要调用其getCurrentUser方法,然后又因为currentUser是null而不得不再给currentUser初始化,如此反复。。。,必然导致StackOverflow。

    简化我遇到的情况,大家可以运行下面的代码来复现这个bug:

    package fastjsonstackoverflow;
    import java.io.Serializable;
    public class MyEntity implements Serializable {
    
        String id;
        MyEntity currentUser;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        /**
         * 即使没有定义length字段,fastjson序列化不会出现异常
         * @return
         */
        public int getLength(){
            return 0;
        }
    
        public MyEntity getCurrentUser() {
            if(null==currentUser){
                currentUser=new MyEntity();
            }
            return currentUser;
        }
    
        public void setCurrentUser(MyEntity currentUser) {
            this.currentUser = currentUser;
        }
    }
    
    package fastjsonstackoverflow;
    import com.alibaba.fastjson.JSONObject;
    public class MainTest {
        public static void main(String[] args) {
            MyEntity entity = new MyEntity();
    //        System.out.println("mydata:"+entity.getCurrentUser());
            System.out.println("mydata:" + JSONObject.toJSONString(entity));
        }
    }

    ps:今天通过查看fastjson源码,了解到java中的移位运算符>> <<,

    <<      :     左移运算符,num << 1,相当于num乘以2

    >>      :     右移运算符,num >> 1,相当于num除以2

    在此做记录。

  • 相关阅读:
    洛谷P2345 奶牛集会
    洛谷P3531 [POI2012]LIT-Letters
    codevs 4163 hzwer与逆序对
    各种读入方式速度比较
    洛谷P1420 最长连号
    TCPDump:捕获并记录特定协议 / 端口
    linux下抓取网页快照
    Pro Android 4 第五章 理解Intent
    UpdatePanel和jQuery不兼容
    RAC 11.2.0.4 安装 遇到 INS-06001
  • 原文地址:https://www.cnblogs.com/buguge/p/10140073.html
Copyright © 2011-2022 走看看