fastjson序列化复杂对象死循环本质是双向引用导致无限递归,默认开启循环检测(v1.2.76+)并用$ref替代重复引用;可通过禁用disablecircularreferencedetect、@jsonfield(serialize=false)、serializefilter或升级fastjson2解决。

Fastjson 序列化复杂对象时出现死循环,本质是对象图中存在**双向引用**(比如 A 持有 B,B 又持有 A),导致序列化器无限递归遍历。默认情况下 Fastjson 不做循环检测,就会栈溢出(StackOverflowError)或卡死。
启用内置循环引用检测
Fastjson 提供了 SerializerFeature.DisableCircularReferenceDetect 的反向开关,默认是关闭的(即开启检测)。但要注意:**v1.2.76+ 版本默认开启循环引用处理,旧版本需手动配置**。
- 推荐显式启用循环检测(兼容所有主流版本):
String json = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue,
SerializerFeature.DisableCircularReferenceDetect); // ❌ 错误:这是禁用!
// ✅ 正确:不传该参数,或显式使用 WriteNonStringKeyAsString 等安全组合
String json = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue);
// 或更稳妥:
String json = JSON.toJSONString(obj,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty);
```
只要不传 DisableCircularReferenceDetect,Fastjson 就会用 $ref 语法替代重复引用,例如:{"id":1,"parent":{"$ref":"$"}} 表示引用根对象。
用 @JSONField 注解断开指定引用
对不需要序列化的反向字段,加 @JSONField(serialize = false) 最直接有效:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
public class User {
private Long id;
private String name;
private List
// 反向引用,不参与序列化
@JSONField(serialize = false)
private User owner; // 比如 Order 中有 user 字段,User 中又有 owner 字段
}
```
也可配合 deserialize = false 控制反序列化行为,避免混淆。
自定义 SerializeFilter 实现精细控制
当需要动态判断是否序列化某字段(比如按上下文、角色、调试模式),可用 PropertyPreFilter 或 SerializeFilter:
PropertyPreFilter filter = (writer, obj, fieldName) -> {
if (obj instanceof User && "owner".equals(fieldName)) {
return false; // 跳过 owner 字段
}
if (obj instanceof Order && "user".equals(fieldName)) {
return false; // 避免 User ↔ Order 循环
}
return true;
};
String json = JSON.toJSONString(obj, filter);
```
升级到 Fastjson2(强烈推荐)
Fastjson 1.x 已停止维护,且循环引用处理逻辑较重、$ref 兼容性差。Fastjson2(com.alibaba.fastjson2:fastjson2)默认更强健:
- 自动识别循环引用,生成标准 JSON(无
$ref),更易被前端解析 - 性能提升明显,API 更简洁(如
JSON.toJSONString(obj)开箱即用) - 支持 JDK 17+,修复大量 1.x 的安全与序列化缺陷
```
迁移成本低:绝大多数 API 向后兼容,只需改包名和导入路径。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










