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

MapStruct嵌套列表Source转扁平化Target带空值校验方案咨询

MapStruct嵌套列表空安全映射方案

下面提供3种支持空值校验、可自定义默认值的实现方案,都可以避免NPE问题:


方案1:Optional链式调用(无需额外自定义方法)

直接在expression中用JDK自带的Optional做全链路空安全校验,链式调用即可自动处理集合为null、集合为空、属性为null的场景,还能通过orElse设置自定义默认值:

@Mapper(imports = Optional.class)
public interface MyMapper {
    @Mapping(target = "name", source = "name")
    @Mapping(target = "otherName", expression = "java(Optional.ofNullable(source.getOthers())" +
            ".filter(list -> !list.isEmpty())" +
            ".map(list -> list.get(0).getOtherName())" +
            ".orElse(\"\"))") // 可自定义默认值
    @Mapping(target = "moreName", expression = "java(Optional.ofNullable(source.getOthers())" +
            ".filter(list -> !list.isEmpty())" +
            ".map(list -> list.get(0).getMores())" +
            ".filter(mores -> !mores.isEmpty())" +
            ".map(mores -> mores.get(0).getMoreName())" +
            ".orElse(\"\"))")
    Target map(Source source);
}

优点:不用写额外的工具方法,代码简洁,全链路自动空校验。


方案2:自定义默认方法(推荐,可读性维护性最高)

在Mapper接口里封装自定义的空校验方法,通过@Named+qualifiedByName绑定映射关系,所有校验逻辑集中管理,可灵活调整规则:

import org.mapstruct.Named;

@Mapper
public interface MyMapper {
    // 自定义获取第一个Other的otherName的方法
    @Named("getFirstOtherName")
    default String getFirstOtherName(Source source) {
        if (source.getOthers() == null || source.getOthers().isEmpty()) {
            return ""; // 自定义默认值
        }
        Other firstOther = source.getOthers().get(0);
        return firstOther.getOtherName() != null ? firstOther.getOtherName() : "";
    }

    // 自定义获取第一个More的moreName的方法
    @Named("getFirstMoreName")
    default String getFirstMoreName(Source source) {
        if (source.getOthers() == null || source.getOthers().isEmpty()) {
            return "";
        }
        Other firstOther = source.getOthers().get(0);
        if (firstOther.getMores() == null || firstOther.getMores().isEmpty()) {
            return "";
        }
        More firstMore = firstOther.getMores().get(0);
        return firstMore.getMoreName() != null ? firstMore.getMoreName() : "";
    }

    @Mapping(target = "name", source = "name")
    @Mapping(target = "otherName", source = "source", qualifiedByName = "getFirstOtherName")
    @Mapping(target = "moreName", source = "source", qualifiedByName = "getFirstMoreName")
    Target map(Source source);
}

优点:逻辑清晰,调试方便,编译期即可检查语法错误,适合复杂校验场景。


方案3:借助第三方集合工具类

如果项目已经引入了Apache Commons、Guava等工具包,也可以直接在表达式中调用工具类做集合空判断:

// 以Apache Commons CollectionUtils为例
@Mapper(imports = {CollectionUtils.class})
public interface MyMapper {
    @Mapping(target = "otherName", expression = "java(CollectionUtils.isEmpty(source.getOthers()) ? \"\" : source.getOthers().get(0).getOtherName())")
    // moreName逻辑同理,多层判断即可
    Target map(Source source);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:54:03