javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 解決方法
阿新 • • 發佈:2018-06-09
子項目 tom could javax tee IT getc 原因 flag
在使用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 解決方法