You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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);
}

关键注意点

  1. 必须显式定义FeatureIn到FeatureOut的单对象映射方法,MapStruct无法自动识别跨层级的列表类型转换;
  2. 务必添加空指针防护逻辑,避免containers或features为空时抛出异常;
  3. age的String转Integer无需额外配置,MapStruct会自动处理基础类型转换。

内容的提问来源于stack exchange,提问作者gregof

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:20:42