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:\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的更多相关文章
- 用自定义注解实现fastjson序列化的扩展
这篇文章起源于项目中一个特殊的需求.由于目前的开发方式是前后端分离的,基本上是通过接口提供各个服务. 而前两天前端fe在开发中遇到了一些问题:他们在处理字符串类型的时间时会出现精度丢失的情况,所以希望 ...
- fastjson序列化排序问题
fastjson序列化,默认是用字母排序, 那么怎么来实现按照自己定义的顺序输出,想要的json串呢? 直接上代码: import com.alibaba.fastjson.annotation.JS ...
- FastJson序列化时过滤字段(属性)的方法总结
FastJson序列化时(即转成JSON字符串时),可以过滤掉部分字段,或者只保留部分字段,方法有很多,下面举一些常用的方法. 方法一.FastJson的注解 @JSONField(serialize ...
- Java基础/利用fastjson序列化对象为JSON
利用fastjson序列化对象为JSON 参考博客:http://blog.csdn.net/zeuskingzb/article/details/17468079 Step1:定义实体类 //用户类 ...
- FastJson序列化对象复杂时出错问题解决
FastJson序列化对象复杂时出错问题解决 针对复杂的对象,如Map<String, List<Map<String, XxxObject<A, B, C>>&g ...
- spring-data-redis注册fastjson序列化工具
使用spring-data-redis的时候,其序列化工具自带:
- FastJson序列化Json自定义返回字段,普通类从spring容器中获取bean
前言: 数据库的字段比如:price:1 ,返回需要price:1元. 这时两种途径修改: ① 比如sql中修改或者是在实体类转json前遍历修改. ②返回json,序列化时候修改.用到的是fastj ...
- FastJson 序列化与反序列化一些说明
最近所属的组需要对接一些征信结构,就涉及到很多中的数据格式,而springmvc中使用的是jackson作为@ResponseBody的依赖jar 但是个人认为fastkson的性能要高于jackso ...
- Fastjson 序列化,反序列化Map对象排序问题(字符串转map,map转字符串)
背景 记录项目中遇到的 关于fastjson jsonobject转string乱序,string转jsonObject乱序问题的解决方案 fastJson issues 问题来源描述参见: http ...
随机推荐
- Angular路由——路由基础
一.路由相关对象 Router和RouterLink作用一样,都是导航.Router是在Controller中用的,RouterLink是在模版中用到. 二.路由对象的位置 1.Routes对象 配置 ...
- Kubernetes 学习1 k8s架构概述
一.概述 1.意思:舵手,飞行员 2.特点 a.自动装箱,自我修复,水平扩展,服务发现和负载均衡,自动发布和回滚. b.密钥和配置管理,存储编排,批量处理执行. 二.架构术语 1.集群 master( ...
- vue 获取dom的css属性值
<template> <div id="topInfo" ref="topInfo" style="width: 200px;hei ...
- 咸鱼入门到放弃7--jsp<二>jsp常用标签
一.JSP标签介绍 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 二.JSP常用标签 ...
- 安全体系(一)—— DES算法详解
本文主要介绍了DES算法的步骤,包括IP置换.密钥置换.E扩展置换.S盒代替.P盒置换和末置换. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(二)——RSA算 ...
- 编译linux内核前用make menuconfig设置时 Unable to find the ncurses ibraries的解决办法
今天在更新CentOS或者Ubuntu的内核时,执行make menuconfig可能看如这样的错误: *** Unable to find the ncurses libraries or the ...
- Metasploit学习记录---Nessus安装部署
1.Nessus介绍 nessus是目前世界上最为流行的漏洞扫描器之一.她提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库.Nessus不同于传统的漏洞扫描软件,可同时在本机或远端上遥控,进行系统的 ...
- Android的Launcher启动流程 “Launcher部分启动流程”
研究代码从:AndroidManifest.xml.自定义的Application.java开始. Android系统启动时,系统需要一个Home应用程序来负责将这些应用程序展示出来:也就是该应用的目 ...
- react-native android textinput显示不全的问题
出现的问题 如下图 原因 android 输入框默认带有上下内边距 解决 将Textinput元素样式的垂直内边距设置为0 paddingVertical: 0
- js之promise讲解
1 Promise概述 Promise对象是CommonJS工作组提出的一种规范,目的是为异步操作提供统一接口. 那么,什么是Promises? 首先,它是一个对象,也就是说与其他JavaScript ...