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

Spring Boot 3中为标准Bean Validation注解注册自定义验证器失败求助

问题描述

在Spring Boot 3.0.4中遇到以下错误:

HV000030: No validator could be found for constraint 'jakarta.validation.constraints.Size' validating type 'com.example.entity.dataType.GenericString'. Check configuration for 'iso3'

已尝试多种方案但毫无进展:

  • 尝试注册自定义约束验证器但未成功
  • 尝试容器元素验证方案同样失败
  • 尝试结合自定义验证器与现有通用验证器的方式,始终无法生效

相关源码如下:

实体类

public class Test {

    @Id
    @Column(name = "id",
            nullable = false)
    private long id;

    @Randomizer(GenericStringValidator.class)
    @Convert(converter = GenericStringConverter.class)
    @JsonSerialize(using = GenericStringSerializer.class)
    @Column(name = "iso3",
            nullable = false,
            length = 3)
    @Size(min = 3,
          max = 3)
    private GenericString iso3;
}

值提取器

@UnwrapByDefault
public class GenericStringValueExtractor implements ValueExtractor<@ExtractedValue(type = String.class) GenericString> {

    @Override
    public void extractValues(GenericString originalValue, ValueExtractor.ValueReceiver receiver) {
        receiver.value(null, originalValue.getValue());
    }
}

@Size验证器实现类

@Component
public class GenericStringSizeConstraintValidator implements ConstraintValidator<Size, GenericString> {

    private int min;

    private int max;

    @Override
    public void initialize(Size parameters) {
        this.min = parameters.min();
        this.max = parameters.max();
        try {
            this.validateParameters();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private boolean check(String value) {
        if (value == null) {
            return true;
        } else {
            int length = value.length();
            return length >= this.min && length <= this.max;
        }
    }

    public boolean isValid(GenericString dataType, ConstraintValidatorContext constraintValidatorContext) {
        if (dataType == null) {
            return true;
        } else {
            return check(((FrameworkDataType<String>) dataType).getValue());
        }
    }

    private void validateParameters() throws Exception {
        if (this.min < 0) {
            throw new Exception("Min Value cannot be nagative");
        } else if (this.max < 0) {
            throw new Exception("Max Value cannot be nagative");
        } else if (this.max < this.min) {
            throw new Exception("Length Value cannot be nagative");
        }
    }
}

自定义ValidatorFactoryBean

@Component
public class ValidatorFactoryBean extends LocalValidatorFactoryBean {

    @Autowired
    private GenericStringSizeConstraintValidator genericStringSizeConstraintValidator;

    @Override
    protected void postProcessConfiguration(Configuration<?> configuration) {
        super.postProcessConfiguration(configuration);

        configuration.addValueExtractor(new GenericStringSizeConstraintValidator());
        configuration.addValueExtractor(new GenericNameSizeConstraintValidator());

        HibernateValidatorConfiguration configurationH = Validation.byProvider(HibernateValidator.class)
                                                                   .configure();

        ConstraintMapping constraintMapping = configurationH.createConstraintMapping();

        constraintMapping.constraintDefinition(Size.class)
                         .includeExistingValidators(true)
                         .validatedBy(GenericStringSizeConstraintValidator.class);

        configurationH.addMapping(constraintMapping);
    }
}

编辑1:找到相关文章,但创建META-INF/services/javax.validation.ConstraintValidator文件的方案在Spring Boot 3中无效。


解决方案

你的配置存在几个关键问题,导致自定义验证器无法被正确识别:

1. 修复值提取器注册错误

你错误地将验证器实例当作值提取器注册,应该注册的是GenericStringValueExtractor,而不是GenericStringSizeConstraintValidator。修正代码:

// 替换原有错误的注册逻辑
configuration.addValueExtractor(new GenericStringValueExtractor());

2. 关联约束映射到当前工厂配置

你创建了新的HibernateValidatorConfiguration实例但未关联到当前LocalValidatorFactoryBean的配置。正确做法是将约束映射添加到传入的configuration对象:

@Override
protected void postProcessConfiguration(Configuration<?> configuration) {
    super.postProcessConfiguration(configuration);

    // 注册正确的值提取器
    configuration.addValueExtractor(new GenericStringValueExtractor());

    // 强转为HibernateValidatorConfiguration
    HibernateValidatorConfiguration hibernateConfig = (HibernateValidatorConfiguration) configuration;
    ConstraintMapping constraintMapping = hibernateConfig.createConstraintMapping();

    // 为Size约束添加自定义验证器,保留原有验证器
    constraintMapping.constraintDefinition(Size.class)
                     .includeExistingValidators(true)
                     .validatedBy(GenericStringSizeConstraintValidator.class);

    // 将映射添加到当前配置
    hibernateConfig.addMapping(constraintMapping);
}

3. 修正ServiceLoader文件路径(可选)

Spring Boot 3使用Jakarta EE API,ServiceLoader文件路径应为META-INF/services/jakarta.validation.ConstraintValidator,而非javax.validation.ConstraintValidator。文件内容添加你的验证器全类名:

com.example.xxx.GenericStringSizeConstraintValidator

4. 移除验证器的@Component注解

若通过代码或ServiceLoader注册验证器,无需给GenericStringSizeConstraintValidator添加@Component注解,避免Spring重复管理实例。

验证生效

启动应用后,触发Test实体的验证(如通过@Valid绑定请求参数或直接调用Validator.validate()),检查错误是否消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:15:03