如何让ModelMapper映射失败时设目标字段为null而非抛MappingException?
解决ModelMapper映射失败时设null并继续映射的方案
核心思路
针对第三方API中容易出问题的字段类型(Short/Byte、数值与字符串混传等),通过自定义全局转换器捕获转换异常,返回null而非抛出异常;同时配置ModelMapper确保单个字段映射失败时不终止整个流程,既保留内部数据标准的严格性,又兼容第三方的脏数据。
具体实现步骤
1. 基础配置:让ModelMapper容忍单字段失败
先调整ModelMapper的核心配置,关闭严格中断机制,同时保持内部数据的匹配标准:
ModelMapper modelMapper = new ModelMapper(); modelMapper.getConfiguration() .setMatchingStrategy(MatchingStrategies.STRICT) // 维持内部字段的严格匹配规则 .setFieldMatchingEnabled(true) // 若使用字段映射而非getter/setter需开启 .setAmbiguityIgnored(true) // 忽略字段歧义,避免额外异常 .setSkipNullEnabled(false); // 保留源null值的默认处理逻辑
2. 自定义全局容错转换器
为高频出问题的类型对(如Object转Short、Object转Byte)编写转换器,捕获类型不匹配、值超范围的异常,返回null:
示例:Object转Short的容错转换器
Converter<Object, Short> safeShortConverter = context -> { Object source = context.getSource(); if (source == null) return null; try { // 兼容Number、String等多种源类型 if (source instanceof Number) { long val = ((Number) source).longValue(); return (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) ? ((Number) source).shortValue() : null; } else if (source instanceof String) { String str = ((String) source).trim(); if (str.isEmpty()) return null; long val = Long.parseLong(str); return (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) ? (short) val : null; } return null; } catch (NumberFormatException | ClassCastException e) { // 捕获所有转换异常,返回null return null; } }; // 注册为全局转换器 modelMapper.addConverter(safeShortConverter);
同理实现Byte的容错转换器
复制上述逻辑,将Short替换为Byte,调整数值范围为Byte.MIN_VALUE到Byte.MAX_VALUE即可。
字符串转数值的容错处理
如果内部数值字段可能收到字符串类型的源数据,可添加如下转换器:
Converter<Object, Integer> safeIntegerConverter = context -> { Object source = context.getSource(); if (source == null) return null; try { if (source instanceof Number) { return ((Number) source).intValue(); } else if (source instanceof String) { String str = ((String) source).trim(); return str.isEmpty() ? null : Integer.parseInt(str); } return null; } catch (NumberFormatException | ClassCastException e) { return null; } }; modelMapper.addConverter(safeIntegerConverter);
3. 特定字段的局部处理(可选)
若个别字段需要特殊逻辑,可通过TypeMap单独配置,覆盖全局规则:
modelMapper.typeMap(ThirdPartyApiDto.class, InternalSystemEntity.class) .addMappings(mapper -> { // 当源值超出Short范围时,目标字段设为null mapper.when(ctx -> { Object sourceVal = ctx.getSource(); return sourceVal instanceof Number && (((Number) sourceVal).longValue() < Short.MIN_VALUE || ((Number) sourceVal).longValue() > Short.MAX_VALUE); }).map(ThirdPartyApiDto::getRiskyShortField, (dest, unused) -> dest.setInternalShortField(null)); // 正常情况下的映射逻辑 mapper.map(ThirdPartyApiDto::getRiskyShortField, InternalSystemEntity::setInternalShortField); });
效果验证
配置完成后,第三方API返回的脏数据(如超范围数值、类型不匹配值)会被转换为null,其他字段的映射不受影响,不会触发MappingException中断整个转换流程。
内容的提问来源于stack exchange,提问作者Rafael Lima
相关产品推荐
相关产品推荐

