版本不匹配引發的坑:javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint


發現一個API報了錯:

javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotEmpty' validating type 'java.lang.String'. Check configuration for 'cancelReason'
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.throwExceptionForNullValidator(ConstraintTree.java:229) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorNoUnwrapping(ConstraintTree.java:310) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorInstanceForAutomaticUnwrapping(ConstraintTree.java:244) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:163) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:116) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:87) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:621) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:584) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:528) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:496) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:461) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:411) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:208) ~[hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
    at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:103) ~[spring-context-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.boot.autoconfigure.web.WebMvcValidator.validate(WebMvcValidator.java:64) ~[spring-boot-autoconfigure-1.5.13.RELEASE.jar:1.5.13.RELEASE]
    at org.springframework.validation.DataBinder.validate(DataBinder.java:895) ~[spring-context-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.validateIfApplicable(AbstractMessageConverterMethodArgumentResolver.java:270) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:133) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) ~[spring-web-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[spring-web-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:883) [spring-webmvc-4.3.17.RELEASE.jar:4.3.17.RELEASE]

一、Spring MVC的參數校驗
Spring的參數校驗會用到兩個庫:validation-api,hibernate-validator
validation-api是一套標准,hibernate-validator實現了此標准。
JSR-303 是Java EE 6 中的一項子規范,叫做BeanValidation,官方參考實現是hibernate-validator。

二、HV000030: No validator
報這個錯,一般有兩種情況:
(1)約束與對象屬性不匹配,譬如在String 上使用javax.validation.constraints.Future就會報這個錯
(2)真的是沒有相關的Validator

一下子覺得很奇怪,難道javax.validation.constraints.NotEmpty不能用在java.lang.String??

這有什么錯呢!!

真的是沒有Validator?

如果有,會是這樣的,以javax.validation.constraints.Future為例:

 

 

還真沒有!!但是@NotEmpty是有兩個的
看了下線上在跑的的API,發現使用的是org.hibernate.validator.constraints.NotEmpty。
剛才也看到了,也是沒有對應Validator
但是有一些與javax.validation.constraints.NotEmpty不一樣的地方:使用了兩個元約束@NotNull和@Size(min=1)
 

也就是一個校驗不需要一個專門的Validator也是可以的?

 
三、ComposingConstraints【組合約束】

打斷點看了下,hibernate-validator在處理約束時,使用組合約束的概念【可擴展性好強】。
具體工作流程如下:
(1)先遞歸校驗組合約束。譬如org.hibernate.validator.constraints.NotEmpty中的@NotNull和@Size(min=1)
(2)校驗主約束,如果有則校驗;否則,跳過。譬如org.hibernate.validator.constraints.NotEmpty
(3)處理組合約束的校驗結果。有三種策略:OR,AND,ALL_FALSE
org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree#validateConstraints(org.hibernate.validator.internal.engine.ValidationContext<T>, org.hibernate.validator.internal.engine.ValueContext<?,V>, java.util.Set<javax.validation.ConstraintViolation<T>>)

 

 

org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree#validateComposingConstraints

 

四、為什么會有這個一定會報錯的javax.validation.constraints.NotEmpty呢?

大家都知道Spring Boot幫助我們做了一件臟活、累活【感恩】:依賴包的版本管理。難道此處有bug?
使用IDEA中的Maven Helper插件看一下:

Jump to Source,原來是pom.xml中顯式引入2.0.1.Final的validator-api

 Spring Boot1.5.13中使用的是1.1.0.Final

問了下當時添加此依賴的同學,反饋是從老項目中繼承過來的,當時是為了解決JPA的一個問題。不過現在已經全部改用Mybatis,那么這個是可以去掉的。
把項目所有的微服務check了一遍,發現只有這個項目有。
去掉並回歸了下,相關接口並沒有受到影響。OK,收工

 補充:
validation-api,hibernate-validator依賴及匹配的版本:

 

 

 

 

 

 

 

 

參考:
https://www.cnblogs.com/softidea/p/5907423.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM