如何用Mapstruct实现MyOM与MyEntity父子结构列表的双向映射?
使用MapStruct实现List与List的双向映射
场景说明
MyOM采用树形结构:父节点包含子节点集合,子节点无下级节点;MyEntity采用扁平结构:通过parent字段关联父实体,根实体的parent为null。需要实现两种结构列表的双向转换。
实体与DTO定义
类结构如下:
class MyOM { private String label; private Set<MyOM> children; // 省略getter、setter、构造方法 } class MyEntity { private String label; private MyEntity parent; // 省略getter、setter、构造方法 }
映射实现(Mapper接口)
MapStruct无法自动处理树形与扁平结构的转换,需结合自定义逻辑实现:
@Mapper(config = ServiceMapperConfig.class) public interface IMyObjectMapper { // 基础转换:单个MyEntity → MyOM MyOM entityToOm(MyEntity entity); // 基础转换:单个MyOM → MyEntity MyEntity omToEntity(MyOM om); // MyEntity列表 → MyOM列表:组装树形结构 default List<MyOM> mapEntities(List<MyEntity> entities) { // 按父节点分组,快速查找子节点 Map<MyEntity, List<MyEntity>> parentToChildren = entities.stream() .filter(e -> e.getParent() != null) .collect(Collectors.groupingBy(MyEntity::getParent)); // 处理所有根节点(parent为null),构建树形结构 return entities.stream() .filter(e -> e.getParent() == null) .map(this::buildOmTree) .collect(Collectors.toList()); } // 构建单个MyOM树形节点 default MyOM buildOmTree(MyEntity parentEntity) { MyOM parentOm = entityToOm(parentEntity); // 查找并转换当前父实体的子节点 List<MyEntity> childEntities = parentToChildren.getOrDefault(parentEntity, Collections.emptyList()); Set<MyOM> childOms = childEntities.stream() .map(this::entityToOm) .collect(Collectors.toSet()); parentOm.setChildren(childOms); return parentOm; } // MyOM列表 → MyEntity列表:拆解树形为扁平结构 default List<MyEntity> mapOMs(List<MyOM> oms) { List<MyEntity> entities = new ArrayList<>(); // 遍历所有根OM,处理自身及子节点 for (MyOM rootOm : oms) { processOmNode(rootOm, null, entities); } return entities; } // 处理单个MyOM节点,转换为Entity并设置父节点 default void processOmNode(MyOM om, MyEntity parentEntity, List<MyEntity> entities) { MyEntity entity = omToEntity(om); entity.setParent(parentEntity); entities.add(entity); // 处理子节点(子节点无后代,直接遍历) if (om.getChildren() != null) { for (MyOM childOm : om.getChildren()) { processOmNode(childOm, entity, entities); } } } }
代码说明
MyEntity → MyOM:
- 先通过流式API将子实体按父实体分组,避免重复遍历查找
- 筛选出根实体(
parent为null),逐个构建树形结构,为每个父OM添加对应子OM集合
MyOM → MyEntity:
- 遍历每个根OM,递归处理自身及所有子OM
- 转换每个OM为Entity时,设置对应父Entity,最终收集所有Entity到扁平列表中
注意事项
- 确保实体类的getter/setter方法齐全,MapStruct依赖这些方法完成属性映射
- 若子节点存在多层嵌套,上述递归逻辑可兼容多层场景
- 数据量较大时,递归可能引发栈溢出,可将递归改为迭代实现
内容的提问来源于stack exchange,提问作者jeangr
相关产品推荐
相关产品推荐

