zoukankan      html  css  js  c++  java
  • javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 解决方法

    在使用hibernate validator进行参数有效性校验的时候,我们有时候会遇到javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint ,比如,在我们的应用中,使用了自定义注解Dict对枚举进行有效性校验,因为定义的Dict应用于String类型,例如:

    package com.yidoo.base.metadata.validate;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Target({ElementType.FIELD})
    @Retention(value = RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = { DictValidator.class })
    @Documented
    public @interface Dict {
        /**
         * 数据字典的标准名称, 驼峰式或者下划线分隔都可以
         * @return
         */
        String dictName();
        
        /**
         * 表示验证数据字典有效性的范围为明确指定的字段名。<br />
         * 用于一些特殊场景, 比如订单状态中有作废, 但是这些有效性我们不希望业务订单明确传递这个值, <br />
         * 所以要过滤掉, 适用于重用数据字典, 但是取值范围为子集的情况。
         * 默认为空,表示所有子项目都有效。相当于除非声明某些有效,否则全部有效。
         * @return
         */
        String fieldName() default "";
        
        String message() default "{数据字典取值不合法,请参考标准数据字典管理}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
    }
    package com.yidoo.base.metadata.validate;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    import com.yidoo.base.metadata.cons.DictUtils;
    
    public class DictValidator implements ConstraintValidator<Dict, String> {
        
        private String dictName;
        
        @Override
        public void initialize(Dict dictAnno) {
            this.dictName = dictAnno.dictName();
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (DictUtils.isValid(dictName, value)) {
                return true;
            }
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("该字段的当前值" + value + "不在数据字典" + dictName + "的有效取值范围内, 有效值为:[" + DictUtils.getDictKeys(dictName) + "]").addConstraintViolation();
            return false;
        }
    
    }

    在如下校验中就会失败:

        @NotNull
        @ValidServices(services = IOperatorService.SAVE)
        @Dict(dictName="bool_int")
        private Integer loginFlag;

     如下:

    javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'com.yidoo.base.metadata.validate.Dict' validating type 'java.lang.Integer'. Check configuration for 'firstTimeFlag'
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.throwExceptionForNullValidator(ConstraintTree.java:228)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorNoUnwrapping(ConstraintTree.java:309)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorInstanceForAutomaticUnwrapping(ConstraintTree.java:243)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:164)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:109)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:88)
        at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:617)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:582)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validatePropertyForSingleDefaultGroupElement(ValidatorImpl.java:1051)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validatePropertyForDefaultGroup(ValidatorImpl.java:1019)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validatePropertyForCurrentGroup(ValidatorImpl.java:936)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validatePropertyInContext(ValidatorImpl.java:824)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateProperty(ValidatorImpl.java:223)
        at com.yidoo.utils.ValidationUtils.validatePropertyInternal(ValidationUtils.java:56)
        at com.yidoo.utils.ValidationUtils.validateEntityByServiceId(ValidationUtils.java:99)
        at com.yidoo.utils.LfValidUtil.newValid(LfValidUtil.java:37)
        at com.yidoo.k3c.base.service.ClientService.insert(ClientService.java:129)
        
        

    当遇到有些设计,取值为布尔类型,0代表false,1代表true的时候,采用了Integer类型,使用Dict注解的时候就会出现上述错误,对于该异常,原因是Dict的校验器参数String不匹配Integer,要解决该异常,我们可以再定义一个针对Integer有效性校验的IntDict,如下所示:

    package com.yidoo.base.metadata.validate;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Target({ElementType.FIELD})
    @Retention(value = RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = { IntDictValidator.class })
    @Documented
    public @interface IntDict {
        /**
         * 数据字典的标准名称, 驼峰式或者下划线分隔都可以
         * @return
         */
        String dictName();
        
        /**
         * 表示验证数据字典有效性的范围为明确指定的字段名。<br />
         * 用于一些特殊场景, 比如订单状态中有作废, 但是这些有效性我们不希望业务订单明确传递这个值, <br />
         * 所以要过滤掉, 适用于重用数据字典, 但是取值范围为子集的情况。
         * 默认为空,表示所有子项目都有效。相当于除非声明某些有效,否则全部有效。
         * @return
         */
        String fieldName() default "";
        
        String message() default "{数据字典取值不合法,请参考标准数据字典管理}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
    }
    package com.yidoo.base.metadata.validate;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    import com.yidoo.base.metadata.cons.DictUtils;
    
    public class IntDictValidator implements ConstraintValidator<IntDict, Integer> {
        
        private String dictName;
        
        @Override
        public void initialize(IntDict dictAnno) {
            this.dictName = dictAnno.dictName();
        }
    
        @Override
        public boolean isValid(Integer value, ConstraintValidatorContext context) {
            if (DictUtils.isValid(dictName, String.valueOf(value))) {
                return true;
            }
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("该字段的当前值" + value + "不在数据字典" + dictName + "的有效取值范围内, 有效值为:[" + DictUtils.getDictKeys(dictName) + "]").addConstraintViolation();
            return false;
        }
    
    }

    注:为什么不直接采用正则校验呢?因为对于很多枚举类型来说,取值范围是业务随机定义的,此时可能依赖于常量、枚举类甚至动态加载到缓存的定义进行校验(看不同系统的设计约定和规范)。

  • 相关阅读:
    Linux系列教程-----Linux安装centos6.8
    laravel 常见操作
    git 拖下laravel 代码后报错 Warning: require(D:WWWlaravelootstrap/../vendor/autoload.php
    phpunit单元测试
    linux环境配置
    window 环境下在虚拟机上安装php环境
    第三方登录---微信(使用laravel插件)
    h5页面在ios机上禁止长按复制
    JS 中根据iframe子页面自动iframe高度
    关于JS解析编历JSON数组(含多维数组)
  • 原文地址:https://www.cnblogs.com/zhjh256/p/9160473.html
Copyright © 2011-2022 走看看