今天在一个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:\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。

简化我遇到的情况,大家可以运行下面的代码来复现这个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

在此做记录。

fastjson序列化出现StackOverflowError的更多相关文章

  1. 用自定义注解实现fastjson序列化的扩展

    这篇文章起源于项目中一个特殊的需求.由于目前的开发方式是前后端分离的,基本上是通过接口提供各个服务. 而前两天前端fe在开发中遇到了一些问题:他们在处理字符串类型的时间时会出现精度丢失的情况,所以希望 ...

  2. fastjson序列化排序问题

    fastjson序列化,默认是用字母排序, 那么怎么来实现按照自己定义的顺序输出,想要的json串呢? 直接上代码: import com.alibaba.fastjson.annotation.JS ...

  3. FastJson序列化时过滤字段(属性)的方法总结

    FastJson序列化时(即转成JSON字符串时),可以过滤掉部分字段,或者只保留部分字段,方法有很多,下面举一些常用的方法. 方法一.FastJson的注解 @JSONField(serialize ...

  4. Java基础/利用fastjson序列化对象为JSON

    利用fastjson序列化对象为JSON 参考博客:http://blog.csdn.net/zeuskingzb/article/details/17468079 Step1:定义实体类 //用户类 ...

  5. FastJson序列化对象复杂时出错问题解决

    FastJson序列化对象复杂时出错问题解决 针对复杂的对象,如Map<String, List<Map<String, XxxObject<A, B, C>>&g ...

  6. spring-data-redis注册fastjson序列化工具

    使用spring-data-redis的时候,其序列化工具自带:

  7. FastJson序列化Json自定义返回字段,普通类从spring容器中获取bean

    前言: 数据库的字段比如:price:1 ,返回需要price:1元. 这时两种途径修改: ① 比如sql中修改或者是在实体类转json前遍历修改. ②返回json,序列化时候修改.用到的是fastj ...

  8. FastJson 序列化与反序列化一些说明

    最近所属的组需要对接一些征信结构,就涉及到很多中的数据格式,而springmvc中使用的是jackson作为@ResponseBody的依赖jar 但是个人认为fastkson的性能要高于jackso ...

  9. Fastjson 序列化,反序列化Map对象排序问题(字符串转map,map转字符串)

    背景 记录项目中遇到的 关于fastjson jsonobject转string乱序,string转jsonObject乱序问题的解决方案 fastJson issues 问题来源描述参见: http ...

随机推荐

  1. 02.Numpy

    01.array # -*- coding: utf-8 -*- """ Numpy 패키지 특징 - 선형대수(벡터, 행렬) 연산에 효과적인 함수 제공 - lis ...

  2. Redis哈希表总结

    本文及后续文章,Redis版本均是v3.2.8 在文章<Redis 数据结构之dict><Redis 数据结构之dict(2)>中,从代码层面做了简单理解.总感觉思路的不够条理 ...

  3. 多线程下载图片,同步下载http://www.importnew.com/15731.html

    package mutiDownload; import java.io.IOException; import java.io.InputStream; import java.io.RandomA ...

  4. 同时使用antd和css module

    同时编译antd和css module,需要设置两次less识别. { test: /\.less$/, exclude: path.resolve(__dirname, './node_module ...

  5. PostgreSQL自学笔记:6 PostgreSQL函数

    6 PostgreSQL函数 6.2 数学函数 abs(x) 绝对值 pi() 圆周率π select abs(-3),pi(); cookie: MySQL中的pi()默认值3.141593, Po ...

  6. Python开发实战PDF

    Python开发实战(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1iP9VmwuzDMfdZTfpupR3CA 提取码:a523 复制这段内容后打开百度网盘手机A ...

  7. 移除K位数字

    1.题目来源:选自LeetCode 402: 2.问题描述: 3.问题分析 通过分析我们可以得出这样的结论:如果后一个数字比前面的数字小的话,那么我们就要把前面的一个数字删除掉,并且每次把字符串中拆出 ...

  8. __x__(38)0909第五天__雪碧图的制作

    1. 用ps打开目标图片若干. 2. 调整合适的画布大小. 3. 将图片拖曳到一张里. 4. 存储为Web所用格式,选择 png24 .

  9. 自定义 绑定响应函数 解除响应函数 .addEventListener 兼容 .attachEvent

    嗯哼.不多说,直接上代码. // 自定义 绑定响应函数 兼容性封装 Test Already. function bindEventFunc(obj, eventStr, func){ // cons ...

  10. ActiveMQ的安装与使用(单节点)

    1. 安装 JDK 并配置环境变量(略) JAVA_HOME=/usr/local/java/jdk1.7.0_72 2. 下载 Linux 版的 ActiveMQ $ wget http://apa ...