fastjson序列化出現StackOverflowError

今天在一個web項目裏開發功能,記錄日誌用到了fastjson的序列化,把類型爲RetreatRecord的數據對象序列化後打印出來。結果出現StackOverflowError。先貼出來異常堆棧:java

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方法以下:web

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

 

 

問題就出如今了currentUser爲null時給其初始化的這句上。json

debug程序可見,fastjson包裏JSONSerializer.java的以下方法被死循環執行,直到堆棧溢出。this

// D:\workspace\m3\com\alibaba\fastjson\1.2.6\fastjson-1.2.6-sources.jar!\com\alibaba\fastjson\serializer\JSONSerializer.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。spa

 

簡化我遇到的狀況,你們能夠運行下面的代碼來複現這個bug:debug

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乘以2code

>>      :     右移運算符,num >> 1,至關於num除以2對象

在此作記錄。blog

相關文章
相關標籤/搜索