如何用MapStruct将PersonIn容器列表首元素的特征列表映射到PersonOut
MapStruct实现PersonIn到PersonOut的嵌套列表映射问题
输入DTO
public class FeatureIn { private String val1; private String val2; } public class ContainerIn { private List<FeatureIn> features; } public class PersonIn { private String name; private String age; private List<ContainerIn> containers; }
输出DTO
public class FeatureOut { private String val1; private String val2; } public class PersonOut { private String name; private Integer age; private List<FeatureOut> features; }
映射需求
实现PersonIn到PersonOut的映射:
name直接映射;age从String类型转换为Integer类型;features需从PersonIn的containers列表(已过滤仅含一个元素)中取首个元素的features列表,转换为PersonOut的features列表(List<FeatureIn>转List<FeatureOut>)。
尝试过的失败配置
方案1
@Mapper(componentModel = "spring") public interface PersonMapper { @Mapping(target = "features", source = "containers.features") PersonOut toPersonOut(PersonIn personIn); }
方案2
@Mapper(componentModel = "spring") public interface PersonMapper { @Mapping(target = "features", expression = "java(personIn.getContainers().get(0).getFeatures())") PersonOut toPersonOut(PersonIn personIn); }
报错信息
方案2编译时生成的代码报错:
List<FeatureOut> features = personIn.getContainers().get(0).getFeatures();
原因是List<FeatureIn>与List<FeatureOut>类型不兼容,添加use = FeaturesMapper.class也无法解决。
正确实现方式
方法1:自定义提取转换方法+注解指定
通过自定义方法完成嵌套列表的提取与类型转换,同时利用MapStruct的基础映射能力处理单对象转换:
@Mapper(componentModel = "spring", imports = {Collections.class, Collectors.class}) public interface PersonMapper { // 定义FeatureIn到FeatureOut的基础映射 FeatureOut toFeatureOut(FeatureIn featureIn); // 自定义方法:提取并转换features列表,包含空指针防护 default List<FeatureOut> extractAndConvertFeatures(PersonIn personIn) { if (personIn.getContainers() == null || personIn.getContainers().isEmpty()) { return Collections.emptyList(); } ContainerIn firstContainer = personIn.getContainers().get(0); if (firstContainer.getFeatures() == null) { return Collections.emptyList(); } return firstContainer.getFeatures().stream() .map(this::toFeatureOut) .collect(Collectors.toList()); } // 主映射方法 @Mapping(target = "features", source = ".", qualifiedByName = "extractAndConvertFeatures") PersonOut toPersonOut(PersonIn personIn); }
方法2:在expression中调用批量转换方法
先定义批量转换方法,再在expression中直接调用完成类型转换:
@Mapper(componentModel = "spring", imports = {Collections.class, Collectors.class}) public interface PersonMapper { FeatureOut toFeatureOut(FeatureIn featureIn); // 批量转换方法 default List<FeatureOut> toFeatureOutList(List<FeatureIn> featureIns) { if (featureIns == null) { return Collections.emptyList(); } return featureIns.stream() .map(this::toFeatureOut) .collect(Collectors.toList()); } // 主映射方法 @Mapping(target = "features", expression = "java(toFeatureOutList(personIn.getContainers().get(0).getFeatures()))") PersonOut toPersonOut(PersonIn personIn); }
关键注意点
- 必须显式定义
FeatureIn到FeatureOut的单对象映射方法,MapStruct无法自动识别跨层级的列表类型转换; - 务必添加空指针防护逻辑,避免
containers或features为空时抛出异常; age的String转Integer无需额外配置,MapStruct会自动处理基础类型转换。
内容的提问来源于stack exchange,提问作者gregof
相关产品推荐
相关产品推荐

