You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多DTO映射实体时出现java.lang.StackOverflowError问题求助

问题根源:双向关联导致的无限递归栈溢出

你遇到的StackOverflowError是实体双向关联引发的无限递归映射导致的,和多对象同时映射无关,具体循环路径如下:

  1. 调用NoteEntityToDtoGet映射Note时,会触发GroupEntityToDtoGet映射关联的Group
  2. 在GroupEntityToDtoGet方法中,又会调用NoteConvertList映射Group关联的所有Note列表
  3. NoteConvertList会遍历每个Note并再次调用NoteEntityToDtoGet,形成无限循环,直到JVM栈内存耗尽

单独创建对象时正常,是因为创建场景使用的DTO(比如GroupCreationDTO)没有包含反向关联字段(比如没有notes列表),不会触发递归链。

修复方案

方案1:截断循环链,移除不必要的反向关联映射

如果业务不需要在GroupDTO中返回关联的Note列表,直接修改GroupEntityToDtoGet方法:

public GroupDTO GroupEntityToDtoGet(Group group) {
    GroupDTO groupDTO = new GroupDTO();
    groupDTO.setId(group.getId());
    groupDTO.setName(group.getName());
    groupDTO.setUser(UserEntityToDtoGet(group.getUser()));
    groupDTO.setTags(TagConvertSet(group.getTags()));
    // 移除notes映射,截断递归循环
    // groupDTO.setNotes(NoteConvertList(group.getNotes()));
    return groupDTO;
}

方案2:为不同场景创建精简版DTO

如果需要在Group中展示Note信息,但不需要完整的NoteDTO(包含Group关联),可以创建仅含基础字段的精简DTO:

// 新增精简版NoteDTO
public class NoteSimpleDTO {
    private Long id;
    private String title;
    private String description;
    // 省略getter/setter
}

// 在ObjectMapper中新增对应映射方法
public NoteSimpleDTO NoteEntityToSimpleDto(Note note) {
    NoteSimpleDTO dto = new NoteSimpleDTO();
    dto.setId(note.getId());
    dto.setTitle(note.getTitle());
    dto.setDescription(note.getDescription());
    return dto;
}

// 修改GroupEntityToDtoGet中的Note列表映射
public GroupDTO GroupEntityToDtoGet(Group group) {
    GroupDTO groupDTO = new GroupDTO();
    groupDTO.setId(group.getId());
    groupDTO.setName(group.getName());
    groupDTO.setUser(UserEntityToDtoGet(group.getUser()));
    // 映射为精简版NoteDTO,避免反向关联Group
    groupDTO.setNotes(group.getNotes().stream()
            .map(this::NoteEntityToSimpleDto)
            .collect(Collectors.toList()));
    groupDTO.setTags(TagConvertSet(group.getTags()));
    return groupDTO;
}

方案3:添加递归防护(适用于必须保留完整关联的场景)

用集合记录已处理的对象ID,避免重复映射:

// 重载映射方法,传入已处理ID集合
public NoteDTO NoteEntityToDtoGet(Note note, Set<Long> processedNoteIds) {
    if (processedNoteIds.contains(note.getId())) {
        // 已处理过,返回基础信息避免递归
        NoteDTO dto = new NoteDTO();
        dto.setId(note.getId());
        dto.setTitle(note.getTitle());
        return dto;
    }
    processedNoteIds.add(note.getId());
    
    NoteDTO noteDTO = new NoteDTO();
    noteDTO.setId(note.getId());
    noteDTO.setTitle(note.getTitle());
    noteDTO.setDescription(note.getDescription());
    // 传递已处理集合给Group映射
    noteDTO.setGroup(GroupEntityToDtoGet(note.getGroup(), processedNoteIds));
    noteDTO.setTags(TagConvertSet(note.getTags()));
    return noteDTO;
}

// 重载Group映射方法
public GroupDTO GroupEntityToDtoGet(Group group, Set<Long> processedNoteIds) {
    GroupDTO groupDTO = new GroupDTO();
    groupDTO.setId(group.getId());
    groupDTO.setName(group.getName());
    groupDTO.setUser(UserEntityToDtoGet(group.getUser()));
    // 映射Note时传入已处理集合
    groupDTO.setNotes(group.getNotes().stream()
            .map(note -> NoteEntityToDtoGet(note, processedNoteIds))
            .collect(Collectors.toList()));
    groupDTO.setTags(TagConvertSet(group.getTags()));
    return groupDTO;
}

// 对外暴露的方法,初始化集合
public NoteDTO NoteEntityToDtoGet(Note note) {
    return NoteEntityToDtoGet(note, new HashSet<>());
}

内容的提问来源于stack exchange,提问作者m_novak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:18:18