从数据库获取数据时出现JSON无限递归StackOverflowError问题求助
解决Jackson序列化无限递归(StackOverflowError)问题
问题原因
你的Task和User实体存在双向关联:
Task通过assignee字段引用UserUser通过tasks字段引用List<Task>
当Jackson尝试将实体序列化为JSON时,会不断在Task -> User -> Task -> User之间循环遍历,最终触发StackOverflowError。
解决方案
方法1:使用Jackson双向关联注解
方案1a:用@JsonIgnore忽略反向关联
在User的tasks字段上添加@JsonIgnore,序列化User时会跳过tasks列表,打断循环:
@Entity @Table(name = "tbl_user") public class User { // ... 其他字段 @JsonIgnore @OneToMany(mappedBy = "assignee", cascade = CascadeType.ALL, orphanRemoval = true) private List<Task> tasks; // ... }
方案1b:用@JsonManagedReference和@JsonBackReference区分主次关联
- 在主动序列化的关联方(如
Task的assignee)添加@JsonManagedReference - 在反向关联方(
User的tasks)添加@JsonBackReference,该字段会被Jackson忽略
// Task类 @ManyToOne @JoinColumn(name = "user_id") @JsonManagedReference private User assignee; // User类 @JsonBackReference @OneToMany(mappedBy = "assignee", cascade = CascadeType.ALL, orphanRemoval = true) private List<Task> tasks;
方法2:完善DTO映射(推荐)
你已经在使用TaskResponse作为返回DTO,确保映射时只保留前端需要的字段,不要直接传递整个实体对象:
// TaskResponse示例 public class TaskResponse { private Long taskId; private String title; private String description; private Status status; // 只保留User的必要属性,而非整个User对象 private Long assigneeId; private String assigneeName; private String assigneeEmail; private List<CommentResponse> comments; // getter、setter方法 } // 调整映射逻辑 private TaskResponse mapToTaskResponse(Task task) { TaskResponse response = new TaskResponse(); response.setTaskId(task.getTaskId()); response.setTitle(task.getTitle()); response.setDescription(task.getDescription()); response.setStatus(task.getStatus()); if (task.getAssignee() != null) { response.setAssigneeId(task.getAssignee().getUserId()); response.setAssigneeName(task.getAssignee().getName()); response.setAssigneeEmail(task.getAssignee().getEmail()); } response.setComments(task.getComments().stream() .map(this::mapToCommentResponse) .collect(Collectors.toList())); return response; }
这种方式从根源上避免了实体循环引用,同时符合DTO设计原则,只返回必要数据。
方法3:使用@JsonIdentityInfo保留关联关系
如果需要保留双向关联的序列化,可通过该注解让Jackson识别对象身份,重复对象仅输出ID:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "taskId") @Table(name = "tbl_task") public class Task { // ... } @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId") @Entity @Table(name = "tbl_user") public class User { // ... }
内容的提问来源于stack exchange,提问作者kidulf
相关产品推荐
相关产品推荐

