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

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();
}

三、补充说明

  1. 实体类要求:所有实体类(MatchStrategy、MatchCondition、FilterCondition)需添加Getter/Setter,或使用Lombok的@Data、@Builder注解确保Builder可用。
  2. 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
        );
    }
}
  1. 枚举定义:FilterName、FilterOp枚举需包含YAML中用到的取值,例如:
public enum FilterName {
    CD, ABC, SUV, CUSTOMERNO, AGENTNO
}

public enum FilterOp {
    EQ, NEQ, GT, GTE, LT, LTE
}

内容的提问来源于stack exchange,提问作者Harshita Porwal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:54:50