在使用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;
} }

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

javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 解决方法的更多相关文章

  1. javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint

    使用hibernate validator出现上面的错误, 需要 注意 @NotNull 和 @NotEmpty  和@NotBlank 区别 @NotEmpty 用在集合类上面@NotBlank 用 ...

  2. javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.Size' validating type 'java.util.Date'.

    开始是 javax.validation.UnexpectedTypeException: No validator could be found for type: java.lang.Intege ...

  3. javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint,NotBlank判断不能为空

    java 验证出现如下错误: javax.validation.UnexpectedTypeException: HV000030: No validator could be found for c ...

  4. hibernate 验证异常 javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint

    使用hibernate validator出现上面的错误, 需要 注意 @NotNull 和 @NotEmpty  和@NotBlank 区别 @NotEmpty 用在集合类上面@NotBlank 用 ...

  5. javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint-实体报错

    使用hibernate validator出现上面的错误, 需要 注意 @NotNull 和 @NotEmpty  和@NotBlank 区别 @NotEmpty 用在集合类上面@NotBlank 用 ...

  6. 【SpringMVC】数据校验时,抛出javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.util.Date.

    老魏原创,转载请留言. 原因:给Javabean中的字段注解多余或者错误导致. @NotEmpty @Past @DateTimeFormat(pattern="yyyy-MM-dd&quo ...

  7. 使用spring jpa hibernate框架时报错:javax.validation.UnexpectedTypeException: HV000030

    错误信息: [#%&*^]20190521121942:497.!react:all.,RctJobExecutor-1#D9AA5167921A464CA9DDA14943545426%NA ...

  8. Validation异常:No validator could be found for constraint '.....' validating type 'java.lang.Integer'.

    javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'java ...

  9. spring boot中使用javax.validation以及org.hibernate.validator校验入参

    这里springboot用的版本是:<version>2.1.1.RELEASE</version> 自带了hibernate.validator,所以不用添加额外依赖 1.创 ...

随机推荐

  1. react-router v4 使用 history 控制路由跳转

    问题 当我们使用react-router v3的时候,我们想跳转路由,我们一般这样处理 我们从react-router导出browserHistory. 我们使用browserHistory.push ...

  2. 胸片和CT断层图像是怎么来的?

    本文作者系医科大学青年教师,关注公众号"计算机视觉life"菜单栏回复"医学" 进群交流 如何得到CT断层图像? 相信小伙伴体检的时候都拍过胸片,假如哪个不幸的 ...

  3. (已解决)cocos2d-x 运行时xcode提示错误:"vtable for XXX", referenced from;

    vtable/引用和虚函数相关,今天在添加一个层的时候报了这个错误,很低级的错误,忘了实现虚函数了(谨记!!) 若如果实现了虚函数还依然如此的话,可能是创建的时候忘了钩上 -desktop 选项了,把 ...

  4. Web Audio初步介绍和实践

    Web Audio还是一个比较新的JavaScript API,它和HTML5中的<audio>是不同的,简单来说,<audio>标签是为了能在网页中嵌入音频文件,和播放器一样 ...

  5. Oracle TNS-01190: The user is not authorized to execute the requested listener command

    今天,在玩 lsnrctl命令,是为了了解Oracle的一些配置. 当执行 show inbound_connect_timeout 命令之后,提示了错误信息: TNS-01190: The user ...

  6. c#如何解析时区字符串

    常见时区缩写可参考: http://time.123cha.com/knowledge/6.html 常见时区缩写如下: IDLE +12:00 国际日期变更线,东边  NZDT +13:00 新西兰 ...

  7. Python基础知识摘要

    python字典 增,删,改,查 1.增:XXX[新的key] = value 2.删:DEL XXX[key] 3.改:XXX[已经存在的key] = NewValue 4.查:aList.exte ...

  8. hdu2295DLX重复覆盖+二分

    题目是说 给了n个城市 m个雷达 你只能选择其中的k个雷达进行使用 你可以设置每个雷达的半径,最后使得所有城市都被覆盖,要求雷达的半径尽可能的小(所有雷达的半径是一样的) 二分最小半径,然后每次重新建 ...

  9. codeforces 980B Marlin

    题意: 有一个城市有4行n列,n是奇数,有一个村庄在(1,1),村民的活动地点是(4,n): 有一个村庄在(4,1),村民的活动地点是(1,n): 现在要修建k个宾馆,不能修建在边界上,问能否给出一种 ...

  10. ModelState查看错误字段的信息

    if (!ModelState.IsValid) { List<string> sb = new List<string>(); //获取所有错误的Key List<st ...