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

ModelMapper自定义Converter映射paymentStatus时空指针异常排查

ModelMapper映射Purchase实体触发空指针异常根因与修复

核心报错原因

异常触发的直接原因是自定义Converter执行时未做非空防护,映射链路中传入的source对象为null时,直接强转后调用Purchase.getPurchaseTransactions()方法触发空指针。

典型错误写法

  • 自定义paymentStatus字段转换逻辑的Converter实现中,未对上下文返回的source对象做null判断,直接执行类型强转和关联集合方法调用
  • ModelMapper全局配置未开启空值跳过规则,嵌套映射、级联映射过程中遇到空属性时,仍会强制触发对应属性的Converter执行
  • 业务层toDto转换方法未做入参校验,存在直接将null对象传入modelMapper.map()方法的场景
  • 额外触发场景:Purchase类的purchaseTransactions一对多关联配置为懒加载时,持久化会话关闭后未初始化集合,调用get方法也会抛出类空指针的代理异常

修复步骤

  1. 给自定义Converter增加前置非空校验
// 自定义支付状态转换逻辑
Converter<Purchase, Integer> paymentStatusConverter = context -> {
    Purchase source = context.getSource();
    // 空值直接返回默认值,避免NPE
    if (source == null || source.getPurchaseTransactions() == null) {
        // 可根据业务规则返回默认状态,例如0=未发起支付
        return 0;
    }
    List<Transaction> transactions = source.getPurchaseTransactions();
    // 保留原有支付状态计算逻辑
    // 示例逻辑:全量已支付返回2,部分支付返回1,无交易返回0
    long paidCount = transactions.stream()
            .filter(t -> TransactionStatus.PAID.equals(t.getStatus()))
            .count();
    if (paidCount == 0) return 0;
    if (paidCount == transactions.size()) return 2;
    return 1;
};
  1. 调整ModelMapper全局配置,开启空值跳过
@Configuration
public class ModelMapperConfig {
    @Bean
    public ModelMapper modelMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration()
                .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
                .setFieldMatchingEnabled(true)
                .setSkipNullEnabled(true) // 核心配置:映射时跳过null属性,不触发对应转换器
                .setMatchingStrategy(MatchingStrategies.STRICT);
        // 注册自定义转换器
        modelMapper.addConverter(paymentStatusConverter());
        modelMapper.typeMap(Purchase.class, PurchaseDTO.class)
                .addMappings(mapper -> mapper.using(paymentStatusConverter())
                        .map(source -> source, PurchaseDTO::setPaymentStatus));
        return modelMapper;
    }

    @Bean
    public Converter<Purchase, Integer> paymentStatusConverter() {
        // 此处放上面写的带非空校验的converter逻辑
    }
}
  1. 业务转换入口增加非空拦截
@Service
public class PurchaseService {
    @Resource
    private ModelMapper modelMapper;

    public PurchaseDTO convertToDto(Purchase entity) {
        // 入口处拦截null入参,避免无效映射执行
        if (entity == null) {
            return null;
        }
        return modelMapper.map(entity, PurchaseDTO.class);
    }
}

单元测试校验点

  • 构造测试用例时,无交易记录的Purchase实例要将purchaseTransactions设置为空集合而非null
  • 覆盖入参为null、关联集合为null的边界场景,确认不会抛出转换异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:48:09