YAML中additionalFilters转FilterCondition遇阻:转换器未生效及枚举校验需求
问题解决:自定义Converter不生效+枚举校验启动抛异常
一、修复Converter无法触发的问题
1. 调整属性绑定方式(核心原因)
原配置中直接用@Bean返回List<MatchStrategy>的方式无法触发Spring的类型转换机制,需改用@ConfigurationProperties进行属性绑定:
新增配置属性类
@ConfigurationProperties(prefix = "strategies") public class StrategyProperties { private List<MatchStrategy> strategies; // Getter & Setter public List<MatchStrategy> getStrategies() { return strategies; } public void setStrategies(List<MatchStrategy> strategies) { this.strategies = strategies; } }
修改AppConfig配置类
@Configuration @EnableConfigurationProperties(StrategyProperties.class) @PropertySource(value = "config.yml", factory = YamlPropertySourceFactory.class) public class AppConfig { @Bean public GenericConversionService conversionService(List<Converter<?, ?>> converters) { GenericConversionService conversionService = new GenericConversionService(); converters.forEach(conversionService::addConverter); return conversionService; } }
2. 标记Converter用于配置属性绑定
给自定义Converter添加@ConfigurationPropertiesBinding注解,确保Spring处理配置属性时使用该转换器:
@Component @ConfigurationPropertiesBinding public class MatchConverter implements Converter<Map<String, Object>, MatchCondition> { @Override public MatchCondition convert(Map<String, Object> source) { String condition = (String) source.get("condition"); List<String> additionalFilters = ((List<String>) source.get("additionalFilters")) .stream() .map(Object::toString) .collect(Collectors.toList()); List<FilterCondition> conditions = parseFilters(additionalFilters); return MatchCondition.builder() .condition(condition) .additionalFilters(additionalFilters) .filterConditions(conditions) .build(); } // 解析逻辑见下文枚举校验部分 }
二、实现枚举校验+启动时抛异常
在parseFilters方法中添加枚举转换校验,转换失败时直接抛出IllegalArgumentException,Spring会在启动绑定属性时捕获异常并终止启动:
private List<FilterCondition> parseFilters(List<String> additionalFilters) { return additionalFilters.stream() .filter(Objects::nonNull) .map(this::parseSingleFilter) .collect(Collectors.toList()); } private FilterCondition parseSingleFilter(String filterStr) { // 拆分过滤器字符串(支持==、!=、>、>=、<、<=运算符) String[] parts = filterStr.split("\\s*(==|!=|>|>=|<|<=)\\s*", 3); if (parts.length != 3) { throw new IllegalArgumentException("无效的过滤器格式: " + filterStr); } // 校验FilterName枚举 FilterName filterName; try { filterName = FilterName.valueOf(parts[0].trim().toUpperCase()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("不存在的FilterName枚举值: " + parts[0].trim(), e); } // 校验FilterOp枚举(映射运算符到枚举) FilterOp filterOp = switch (parts[1].trim()) { case "==" -> FilterOp.EQ; case "!=" -> FilterOp.NEQ; case ">" -> FilterOp.GT; case ">=" -> FilterOp.GTE; case "<" -> FilterOp.LT; case "<=" -> FilterOp.LTE; default -> throw new IllegalArgumentException("不支持的运算符: " + parts[1].trim()); }; // 处理值(去除前后引号) String value = parts[2].trim().replaceAll("^['\"]|['\"]$", ""); return FilterCondition.builder() .name(filterName) .op(filterOp) .value(value) .build(); }
三、补充说明
- 实体类要求:所有实体类(
MatchStrategy、MatchCondition、FilterCondition)需添加Getter/Setter,或使用Lombok的@Data、@Builder注解确保Builder可用。 - YAML加载工厂:确保
YamlPropertySourceFactory实现正确,示例如下:
public class YamlPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); factory.setResources(resource.getResource()); Properties properties = factory.getObject(); return new PropertiesPropertySource( name != null ? name : resource.getResource().getFilename(), properties ); } }
- 枚举定义:
FilterName、FilterOp枚举需包含YAML中用到的取值,例如:
public enum FilterName { CD, ABC, SUV, CUSTOMERNO, AGENTNO } public enum FilterOp { EQ, NEQ, GT, GTE, LT, LTE }
内容的提问来源于stack exchange,提问作者Harshita Porwal
相关产品推荐
相关产品推荐

