ModelMapper映射泛型List<String>的抽象DTO报错解决
报错根源定位
- 触发
List无参构造不存在的核心原因:严格匹配模式下,ModelMapper反射解析AbstractBeanDTO<List<String>>的泛型字段value时,错误将目标java.util.List接口识别为可直接实例化的具体类,尝试调用其无参构造创建实例——但List本身是接口,不存在可调用的构造方法,直接抛出异常。 - 之前手动编写的TypeMap映射规则失效的原因:ModelMapper 2.3.5版本中,传统的
mapper.map(源取值方法, 目标赋值方法)写法仍会先走内置集合转换器的逻辑,没有绕开“实例化List接口”的错误流程。 - 之前结合TypeToken编写的逻辑报
source cannot be null的原因:取错了泛型类型——把整个ItemsBeanDTO的类型作为集合映射的目标类型传入,和实际要映射的List元素类型完全不匹配。
落地实现方案
核心逻辑
完全绕开ModelMapper内置集合转换器对List接口的错误实例化流程,对继承AbstractBeanDTO的List泛型子类做专属映射处理,不需要修改原有抽象类结构,也不需要把value字段单独拆成强类型变量声明,且不会影响已配置的严格匹配模式下其他字段的正常映射规则。
具体配置步骤
- 为对应DTO类型创建跳过自动映射的TypeMap,阻断ModelMapper对
value字段的默认自动映射流程:
modelMapper.createTypeMap(ItemsBean.class, ItemsBeanDTO.class) .addMappings(mapper -> mapper.skip(ItemsBeanDTO::setValue));
- 给该TypeMap绑定后置处理逻辑,手动完成value字段的赋值,完全跳过内置转换器的实例化环节:
modelMapper.getTypeMap(ItemsBean.class, ItemsBeanDTO.class) .setPostConverter(context -> { ItemsBean src = (ItemsBean) context.getSource(); ItemsBeanDTO dest = (ItemsBeanDTO) context.getDestination(); // 直接将源对象的value值赋值到目标DTO,无额外类型转换逻辑 dest.setValue((List<String>) src.getValue()); return dest; });
- (可选全局配置)如果项目中有大量List泛型的AbstractBeanDTO子类,可全局注册List类型的实例化器,从根源解决List接口无法实例化的问题:
modelMapper.getConfiguration() .addInstanceConverter(List.class, () -> new ArrayList<>());
踩坑修正
- 之前用TypeToken的写法修正:如果需要用ModelMapper做List的元素类型转换,TypeToken的泛型要和实际要映射的类型匹配,比如要映射String集合就写
new TypeToken<List<String>>(){}.getType(),不要把整个DTO类的类型传进映射方法,否则会触发source null的异常。 - 该方案不需要修改原有抽象类的泛型定义,也不需要把DTO实例单独声明为强类型List变量,完全匹配最初的编码习惯。
内容的提问来源于stack exchange,提问作者Daffy
相关产品推荐
相关产品推荐

