如何配置ModelMapper为所有指定类型属性自动应用转换器?
问题描述
我正尝试配置ModelMapper,使其对所有实现Labelled接口的属性(跨任意实体类)应用特定转换器。目前我可为每个实体定义TypeMap并配置相关属性映射,但希望找到无需新增属性时更新配置的简便方法。现有代码示例如下:
public interface Labelled { String getLabel(); // returns a message code } public class Vegetable implements Labelled { ... } public class Protein implements Labelled { ... } public class Starch implements Labelled { ... } public class Dinner { Vegetable veg; Starch starch; Protein protein; String name; // getters and setters } public class DinnerDto { String veg; String starch; String protein; String name; // get/set } public class LabelledToStringConverter extends AbstractConverter<Labelled, String> { private final MessageSource messageSource; public LabelledToStringConverter(MessageSource messageSource) { this.messageSource = messageSource; } @Override protected String convert(Labelled labelled) { final Locale locale = LocaleContextHolder.getLocale(); final String messageCode = labelled.getLabel(); return messageSource.getMessage(messageCode, null, messageCode, locale); } } @Configuration public class Configuration { @Bean public ModelMapper modelMapper(final MessageSource messageSource) { final ModelMapper mapper = new ModelMapper(); final Converter<Labelled, String> converter = new LabelledToStringConverter(messageSource); mapper.createTypeMap(Dinner.class, DinnerDto.class) .addMappings(map -> { map.using(converter).map(Dinner::getVegetable, DinnerDto::setVegetable); map.using(converter).map(Dinner::getProtein, DinnerDto::setProtein); map.using(converter).map(Dinner::getStarch, DinnerDto::setStarch); }); return mapper; } }
但我希望避免逐个字段甚至逐个类型映射。TypeMap.setPropertyConverter在存在其他类型字段时无效,ModelMapper.addConverter似乎不起作用(我尝试过实现Converter和继承AbstractConverter两种方式)。是否有其他方法配置ModelMapper,让转换器自动应用于所有相关字段,无需显式定义每个映射?
解决方案
可以通过全局转换器+自定义匹配策略实现自动映射,无需逐个字段配置,具体步骤如下:
- 注册全局转换器:直接调用
ModelMapper.addConverter()注册你的LabelledToStringConverter,确保转换器泛型严格匹配Labelled转String。 - 调整匹配策略:设置宽松匹配策略,让ModelMapper更容易识别类型匹配的属性对;同时可通过转换器条件精准控制应用场景。
修改后的配置类示例:
@Configuration public class ModelMapperConfig { @Bean public ModelMapper modelMapper(final MessageSource messageSource) { final ModelMapper mapper = new ModelMapper(); // 设置宽松匹配策略,提升类型转换的触发概率 mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.LOOSE); // 注册全局转换器 Converter<Labelled, String> labelledConverter = new LabelledToStringConverter(messageSource); mapper.addConverter(labelledConverter); // 自定义转换器应用条件:仅当源类型实现Labelled、目标类型为String时生效 mapper.getConfiguration().setConverterCondition(context -> Labelled.class.isAssignableFrom(context.getSourceType()) && String.class.equals(context.getDestinationType()) ); // 无需手动配置Dinner到DinnerDto的字段映射,自动匹配并应用转换器 return mapper; } }
验证效果
现在映射Dinner到DinnerDto时,所有实现Labelled的属性(veg、starch、protein)会自动触发LabelledToStringConverter转换为String,其他类型字段(如name)将按默认规则完成映射。
补充提示
如果需要排除特定属性的自动转换,可单独为该字段创建局部映射覆盖全局规则;若存在多个转换器,通过ConverterCondition能精准控制每个转换器的应用范围,避免类型转换冲突。
内容的提问来源于stack exchange,提问作者Michelle
相关产品推荐
相关产品推荐

