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

如何配置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:47:29