Java 生成 JSON 栈溢出错误 (StackOverflowError) 解决方案
在使用 Java(特别是结合 Hibernate)将实体对象序列化为 JSON 时,若实体间存在一对多或多对一的关联关系且未做特殊处理,极易产生 java.lang.StackOverflowError 栈溢出错误。这是因为 JSON 库在尝试序列化关联对象时会陷入无限递归。
问题复现:为什么会出现栈溢出?
通常我们在 Service 层查询数据并直接转换为 JSON 返回给前端时,代码如下:
List<Comment> commentsList = commentMng.findByArticleId(articleid);
JSONArray jsonMembers = new JSONArray(commentsList);
如果 Comment 实体中的字段都是普通属性,上述操作没有问题。但如果 Comment 表通过外键与 Article 表建立了多对一(Many-to-One)的关系,即一个 Article 包含多个 Comment:
Comment对象中包含一个Article类型的成员变量。Article对象中可能包含一个List<Comment>类型的一级集合。
此时直接使用工具类(如 Jackson、Fastjson 等)自动遍历序列化,程序会沿着“评论→文章→评论列表”的路径无限递归,最终导致 栈内存溢出(StackOverflowError)。
解决方案一:忽略关联字段(推荐)
最简单的做法是在代码层面告诉 JSON 序列化器:“忽略这个会导致循环引用的字段”。根据你项目中使用的 JSON 库不同,注解有所区别:
- Jackson 库:使用
@JsonIgnore注解。 - Fastjson 库:使用
@JSONField(serialize = false)注解。
建议直接在实体类的 Getter 方法或成员变量上加注。当不确定具体使用的是哪个底层库时,可以同时添加两个注解以防遗漏。例如:
// Fastjson 示例
@JSONField(serialize = false)
private Article article;
// Jackson 示例
@JsonIgnore
private List<Comment> commentsList;
解决方案二:手动扁平化数据结构
如果你不仅需要忽略关联字段,还需要将关联信息(如文章标题)提取出来传入前台,则不能简单地将整个 Comment 对象丢进列表。需要手动实例化 JSONObject,将需要的值单独取出放入 Map 或 JsonObject 中。
JSONArray jsonMembers = new JSONArray();
for (Comment comment : commentsList) {
JSONObject jsonObject = new JSONObject();
// 提取基础字段
jsonObject.put("id", comment.getId());
jsonObject.put("content", comment.getContent());
// 提取关联对象信息(转为字符串),避免嵌套对象导致的序列化死循环
if (comment.getArticle() != null) {
jsonObject.put("articleTitle", comment.getArticle().getTitle());
}
jsonMembers.put(jsonObject);
}
这种方法完全切断了序列化器的自动导航机制,确保传输的是扁平的、安全的纯文本或基础数据类型。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









