使用ModelMapper转换嵌套对象时枚举映射失效及验证异常问题
问题原因分析
你遇到的问题核心在于:当处理嵌套对象映射时,ModelMapper并不会自动关联你手动创建的子TypeMap(也就是TypeMap<B, BDTO>),除非你明确告诉它要这么做。
你虽然创建了B -> BDTO的TypeMap,但在A -> ADTO的映射过程中,ModelMapper处理a.b这个嵌套属性时,会默认使用自己的隐式映射规则,而不是你定义好的typeMap2。这就导致typeStr没有被正确映射,同时validate()检查到BDTO.setTypeStr()没有被关联到任何源属性,所以抛出了验证异常。
解决方案
下面提供两种可行的修复方案,你可以根据自己的需求选择:
方案一:在父TypeMap中显式关联子TypeMap
修改A -> ADTO的TypeMap配置,明确指定b属性的映射要使用我们创建的B -> BDTO的TypeMap:
public static void main(String[] args) { A a = new A(); B b = new B(); b.setType(B.Type.A); b.setValue(34); a.setDay(A.Day.FRI); a.setB(b); ModelMapper modelMapper = new ModelMapper(); modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); Converter<Enum, String> enumStringConverter = new AbstractConverter<Enum, String>() { @Override protected String convert(Enum source) { return source != null ? source.name() : null; } }; // 先创建子TypeMap并配置映射规则 TypeMap<B, BDTO> bTypeMap = modelMapper.createTypeMap(B.class, BDTO.class); bTypeMap.addMappings(m -> m.using(enumStringConverter).map(B::getType, BDTO::setTypeStr)); // 创建父TypeMap,同时显式指定b属性的映射使用已定义的子TypeMap TypeMap<A, ADTO> aTypeMap = modelMapper.createTypeMap(A.class, ADTO.class); aTypeMap.addMappings(m -> m.using(enumStringConverter).map(A::getDay, ADTO::setDayStr)); // 关键步骤:关联嵌套属性的映射规则 aTypeMap.addMappings(m -> m.map(A::getB, ADTO::setB)); System.out.println(modelMapper.map(a, ADTO.class)); modelMapper.validate(); }
这样修改后,ModelMapper在处理A.b时会严格遵循我们预先配置好的B -> BDTO规则,typeStr就能正确映射为A,同时validate()也不会再抛出异常。
方案二:注册全局转换器(更简洁)
如果你希望所有枚举到字符串的映射都自动使用同一转换器,并且让ModelMapper自动识别嵌套对象的TypeMap,可以调整配置如下:
public static void main(String[] args) { A a = new A(); B b = new B(); b.setType(B.Type.A); b.setValue(34); a.setDay(A.Day.FRI); a.setB(b); ModelMapper modelMapper = new ModelMapper(); modelMapper.getConfiguration() .setMatchingStrategy(MatchingStrategies.STRICT) // 注册全局枚举转字符串转换器,所有枚举转String都会自动用这个规则 .addConverter(new AbstractConverter<Enum, String>() { @Override protected String convert(Enum source) { return source != null ? source.name() : null; } }); // 仅需指定不同名属性的对应关系,类型转换由全局转换器自动处理 modelMapper.createTypeMap(A.class, ADTO.class) .addMapping(A::getDay, ADTO::setDayStr); modelMapper.createTypeMap(B.class, BDTO.class) .addMapping(B::getType, BDTO::setTypeStr); System.out.println(modelMapper.map(a, ADTO.class)); modelMapper.validate(); }
这里的优势是无需手动关联嵌套TypeMap,ModelMapper会自动检测并应用已创建的B -> BDTO规则,同时全局转换器也减少了重复代码。
验证结果
修改后,控制台输出会变为:
Test.ADTO(dayStr=FRI, b=Test.BDTO(typeStr=A, value=34))
并且modelMapper.validate()不会再抛出任何异常,所有属性都完成了正确映射。
内容的提问来源于stack exchange,提问作者Alessandro Dionisi
相关产品推荐
相关产品推荐

