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

Javax Validator多@Constraint接口报错:同一类型仅允许一个验证器

解决HV000150:同一个约束注解不能为同一类型绑定多个验证器

你遇到的错误提示:

HV000150: The constraint NirValidator defines multiple validators for the type NirResource: NirCalculCleConstraint, NirBrutLongueurConstraint. Only one is allowed

核心原因是Hibernate Validator的规则限制:同一个自定义约束注解,针对同一个目标校验类型,只能绑定一个验证器实现类。你现在的两个验证器NirBrutLongueurConstraint和NirCalculCleConstraint都实现了ConstraintValidator<NirValidator, NirResource>,也就是都是为NirValidator注解、校验NirResource类型服务的,这就违反了这个规则。

虽然@Constraint的validatedBy参数是数组,但它的设计目的是支持同个注解校验不同类型(比如一个注解既可以校验String,也可以校验Integer,各自对应不同的验证器),不是让同个类型用多个验证器。

下面给两种可行的解决办法:


方法一:拆分独立的约束注解

把长度校验和校验码校验拆成两个独立的自定义约束,各自绑定对应的验证器,然后在需要校验的字段上同时使用这两个注解。

1. 长度校验的注解与验证器

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NirBrutLongueurConstraint.class)
public @interface NirLongueurValide {
    String message() default "NIR长度不符合要求";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class NirBrutLongueurConstraint implements ConstraintValidator<NirLongueurValide, NirResource> {
    private static final int LONGUEUR_MIN_NIR = 13;
    private static final int LONGUEUR_MAX_NIR = 15;

    @Override
    public boolean isValid(NirResource value, ConstraintValidatorContext context) {
        return value == null || value.toString().length() == LONGUEUR_MIN_NIR || value.toString().length() == LONGUEUR_MAX_NIR;
    }
}

2. 校验码校验的注解与验证器

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NirCalculCleConstraint.class)
public @interface NirCleValide {
    String message() default "NIR校验码不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class NirCalculCleConstraint implements ConstraintValidator<NirCleValide, NirResource> {
    private static final int CONSTANTE_CALCUL_CLE_NIR = 97;

    private int calculerCle(NirResource value) {
        return (int) (CONSTANTE_CALCUL_CLE_NIR - ((Long.parseLong(value.toString(false))) % CONSTANTE_CALCUL_CLE_NIR));
    }

    @Override
    public boolean isValid(NirResource value, ConstraintValidatorContext context) {
        if (value == null) return true;
        // 注意:原代码返回!=,这里修正为==,校验码匹配才通过
        return Integer.parseInt(value.getCleNir()) == calculerCle(value);
    }
}

3. 在字段上使用两个注解

public class SomeEntity {
    @NirLongueurValide
    @NirCleValide
    private NirResource nir;
    // 其他字段...
}

方法二:合并校验逻辑到单个验证器

如果不想拆分注解,可以把两个校验逻辑合并到同一个验证器类中,在isValid方法里依次执行两个校验,只有都通过才返回true,还能分别抛出对应错误提示。

修改后的验证器和注解

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NirCombinedValidator.class)
public @interface NirValidator {
    String message() default "NIR格式不符合要求";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class NirCombinedValidator implements ConstraintValidator<NirValidator, NirResource> {
    private static final int LONGUEUR_MIN_NIR = 13;
    private static final int LONGUEUR_MAX_NIR = 15;
    private static final int CONSTANTE_CALCUL_CLE_NIR = 97;

    private int calculerCle(NirResource value) {
        return (int) (CONSTANTE_CALCUL_CLE_NIR - ((Long.parseLong(value.toString(false))) % CONSTANTE_CALCUL_CLE_NIR));
    }

    @Override
    public boolean isValid(NirResource value, ConstraintValidatorContext context) {
        if (value == null) return true;

        // 先校验长度
        String nirStr = value.toString();
        boolean lengthValid = nirStr.length() == LONGUEUR_MIN_NIR || nirStr.length() == LONGUEUR_MAX_NIR;
        if (!lengthValid) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("NIR长度不符合要求").addConstraintViolation();
            return false;
        }

        // 再校验校验码
        boolean cleValid = Integer.parseInt(value.getCleNir()) == calculerCle(value);
        if (!cleValid) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("NIR校验码不正确").addConstraintViolation();
            return false;
        }

        return true;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 15:35:27