
本文详解如何通过 MapStruct 将 ObjectA 中关联的 List(每项含 Student.number)映射为 ObjectB 的 List 字段,涵盖表达式映射、自定义默认方法及空安全处理。
本文详解如何通过 mapstruct 将 `objecta` 中关联的 `list
在 MapStruct 中,直接将深层嵌套结构(如 ObjectA → List<pool> → Student → number</pool>)映射到扁平目标字段(如 ObjectB.number: List<string></string>)无法仅靠 @Mapping 注解自动完成,因为 MapStruct 默认不支持跨多级集合+对象链的路径解析(例如 "pool.student.number" 会报错)。此时需结合 表达式映射(expression) 与 自定义默认方法(default method) 实现灵活、可读且类型安全的转换。
✅ 推荐实现方式:使用 expression + default 方法
首先定义 Mapper 接口,并在其中声明一个 default 方法用于提取 number 列表:
@Mapper
public interface ObjectMapper {
@Mapping(source = "id", target = "id")
@Mapping(target = "number",
expression = "java(mapPoolToStringList(objectA.getPool()))")
ObjectB mapObjectAtoObjectB(ObjectA objectA);
default List<String> mapPoolToStringList(List<Pool> poolList) {
if (poolList == null) {
return Collections.emptyList();
}
return poolList.stream()
.filter(Objects::nonNull)
.map(Pool::getStudent)
.filter(Objects::nonNull)
.map(Student::getNumber)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}? 关键说明:
expression = "java(...)"允许内联 Java 表达式,直接调用当前接口中定义的default方法;default方法可访问完整 Java 语法(流式处理、空值校验、异常防护),大幅提升健壮性;- 使用
Collections.emptyList()替代new ArrayList()更符合不可变/线程安全最佳实践。
⚠️ 注意事项与最佳实践
-
空值安全必做:
Pool或Student可能为null(尤其在FetchType.EAGER未完全加载或 ORM 延迟代理场景下),务必对poolList、每个Pool、其student及number进行逐层判空; -
避免副作用:
default方法应为纯函数(无状态、无外部依赖),确保线程安全与可测试性; -
替代方案对比:
- ❌ 不推荐
@AfterMapping:逻辑耦合度高,难以复用,且需手动操作目标对象; - ❌ 避免
@IterableMapping组合嵌套:MapStruct 不支持@Mapping(target = "number", source = "pool.student.number")这类三级路径; - ✅ 可选
@Named+qualifiedBy:若该转换逻辑被多处复用,可封装为带注解的独立方法,提升可维护性。
- ❌ 不推荐
✅ 完整调用示例(验证可用性)
ObjectMapper mapper = Mappers.getMapper(ObjectMapper.class); // 构造测试数据 Student s1 = new Student(1L, "S1001"); Student s2 = new Student(2L, "S1002"); Pool p1 = new Pool(1L, s1); Pool p2 = new Pool(2L, s2); ObjectA a = new ObjectA(); a.setId(100L); a.setPool(Arrays.asList(p1, p2)); ObjectB b = mapper.mapObjectAtoObjectB(a); System.out.println(b.getNumber()); // 输出: [S1001, S1002]
最终生成的 ObjectB 实例将正确包含从关联学生中提取的 number 字符串列表,整个过程零反射、编译期校验、高性能且易于调试。

















