MapStruct技术实践:如何将泛型List映射为包含不同类型元素的非泛型List
我刚遇到过几乎一模一样的问题!这里有个完美适配你需求的解决方案——不用反射、手写代码量极少,还能自动兼容未来的规范更新:
核心思路
MapStruct之所以直接赋值你的internalModelList,是因为目标属性是非泛型的raw List,它没法自动推断要把元素转换成什么类型。我们只需要给它明确元素的目标类型,同时利用MapStruct的自动映射能力处理元素转换,就能解决问题。
具体实现步骤
1. 定义内部模型的基础映射方法
首先,为两个包下对应的内部模型定义映射方法——因为你的模型是同一规范生成的,结构完全一致,MapStruct会自动生成这个方法的实现,不用手写任何转换逻辑:
com.mycompany.models.specb.InternalModel map(com.mycompany.models.speca.InternalModel source);
2. 为非泛型List定义专门的映射方法
用@IterableMapping(elementTargetType = ...)注解明确指定列表元素的目标类型,让MapStruct自动遍历源列表并转换每个元素:
import org.mapstruct.IterableMapping; // ... @IterableMapping(elementTargetType = com.mycompany.models.specb.InternalModel.class) List mapInternalModelList(List<com.mycompany.models.speca.InternalModel> source);
3. 完整的Mapper接口
把这些整合到你的主Mapper里,最终代码如下:
import org.mapstruct.IterableMapping; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.util.List; @Mapper public interface ModelSpecMapper { ModelSpecMapper INSTANCE = Mappers.getMapper(ModelSpecMapper.class); // 主模型的转换 ModelSpecB map(ModelSpecA source); // 内部模型的基础转换 com.mycompany.models.specb.InternalModel map(com.mycompany.models.speca.InternalModel source); // 非泛型List的转换,明确元素目标类型 @IterableMapping(elementTargetType = com.mycompany.models.specb.InternalModel.class) List mapInternalModelList(List<com.mycompany.models.speca.InternalModel> source); }
生成的代码效果
MapStruct会为mapInternalModelList生成这样的实现,完全符合预期:
@Override public List mapInternalModelList(List<InternalModel> source) { if ( source == null ) { return null; } List list = new ArrayList(); for ( InternalModel internalModel : source ) { list.add( map( internalModel ) ); } return list; }
适配未来扩展的技巧
因为你的模型是规范自动生成的,未来新增的List属性和内部模型,只需要重复两个步骤:
- 新增对应内部模型的
map方法 - 新增对应List的
@IterableMapping方法
如果想彻底解放双手,可以写一个简单的代码生成脚本(比如用JavaPoet),扫描speca包下的所有模型,自动生成对应的映射方法——这样规范更新后,你只需要跑一遍脚本,Mapper就自动适配了。
这个方案完全没有反射开销,所有转换都是编译期生成的硬编码,完美保留了MapStruct的性能优势,同时满足低代码、自动适配的需求。
内容的提问来源于stack exchange,提问作者hpabst
相关产品推荐
相关产品推荐

