【问题标题】:How do get around a javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: in Spring如何绕过 javax.validation.ValidationException:HV000064:无法实例化 ConstraintValidator:在 Spring
【发布时间】:2020-01-06 09:58:40
【问题描述】:

任何使用过 spring-boot 的人都遇到过这个错误。

javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator:
**<more stack...>**
Caused by: java.lang.NoSuchMethodException: 
com.comapany.package.validator.<init>()

I know it has something to do with this:

任何依赖于 ConstraintValidatorFactory 的约束实现 特定于实现的行为(依赖注入,无 no-arg 构造函数等)不被认为是可移植的。

但我的验证器不能移植,因为它需要 repo 才能工作,所以这不是一个选项。

我尝试向我的验证器添加一个无参数构造函数,但后来我得到了这个:

javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
Caused by: java.lang.NullPointerException

我也尝试过覆盖 LocalValidatorFactoryBean:

@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(ConstraintValidatorFactory validatorFactory) {
        var bean = new LocalValidatorFactoryBean();
        bean.setConstraintValidatorFactory(validatorFactory);
        return bean;
    }

即使 Spring 识别出我的工厂,我仍然会收到该错误 (HV000064)。

另一种选择是在我的无参数构造函数中为我的验证器添加一个具体的 Repo,但这感觉不对。

public Validator(){
    repo = new ConcreteClassOfRepository();
}

那么我该怎么做呢?

编辑(重用代码):

验证码

@Service
@AllArgsConstructor
@NoArgsConstructor
public class UniqueIdValidator implements ConstraintValidator<UniqueId, String> {

    @Autowired
    private SampleRepository repo;


    @Override
    public void initialize(UniqueId constraintAnnotation) {

    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        return !repo.existsById(s);
    }

}

堆栈跟踪

javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.

    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:177)
    at org.hibernate.validator.internal.engine.constraintvalidation.SimpleConstraintTree.validateConstraints(SimpleConstraintTree.java:68)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:73)
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.doValidateConstraint(MetaConstraint.java:127)
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:120)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:552)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:515)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:485)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:447)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:397)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:173)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:116)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80)
    at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:211)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:84)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
    at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:57)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1309)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1389)
    at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1558)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1526)
    at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1574)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.existsById(SimpleJpaRepository.java:327)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:371)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:204)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:657)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:621)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy112.existsById(Unknown Source)
    at com.packageName.ValidationTest.trackingBugCausedByValidatorNotPortable(ValidationTest.java:99)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: java.lang.NullPointerException
    at com.packageName.UniqueIdValidator.isValid(UniqueIdValidator.java:27)
    at com.packageName.UniqueIdValidator.isValid(UniqueIdValidator.java:11)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:171)

样本库

@Repository
public interface SampleRepository extends JpaRepository<SampleEntity, String> {

}

跟踪测试

    @Test
    void trackingBugCausedByValidatorNotPortable() {
        var entity = new SampleEntity();
        entity.setId("an id");
        repo.save(entity);
        repo.delete(entity);
        assertTrue(repo.existsById("an id"));
        fail("Add @UniqueId to SampleEntity and run");
    }

repo.save() 成功, repo.delete() 成功, 但是repo.existsById() 打破了上述异常

CustomConstraintValidatorFactory & ImplementationFactory

public class CustomConstraintValidatorFactory implements ConstraintValidatorFactory {

    private final ConstraintValidatorFactory defaultFactory;
    private final ImplementationFactory[] implementations;

    public CustomConstraintValidatorFactory(ConstraintValidatorFactory defaultFactory, ImplementationFactory... implementations) {
        this.defaultFactory = defaultFactory;
        this.implementations = implementations;
    }

    @Override
    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
        return Arrays.stream(implementations)
            .filter(factory -> factory.supports(key))
            .findFirst()
            .map(ImplementationFactory::create)
            .map(v -> (T) v)
            .orElseGet(() -> defaultFactory.getInstance(key));
    }

    @Override
    public void releaseInstance(ConstraintValidator<?, ?> instance) {
    }
}

public class InheritanceMatchValidatorFactory implements ImplementationFactory {

    Class klass;
    Supplier<ConstraintValidator> validator;

    @Override
    public boolean supports(Class key) {
        return klass.isAssignableFrom(key);
    }

    @Override
    public ConstraintValidator<?, ?> create() {
        return validator.get();
    }

}

【问题讨论】:

  • 你能分享你的验证器代码吗? NPE 堆栈跟踪也会有所帮助。
  • @akortex91 已添加
  • @kbluue ValidationException: HV000064: Unable to instance this 在运行测试期间发生?
  • @ManojKrishna 在测试期间是的

标签: java spring spring-boot


【解决方案1】:

您能否尝试在您的测试类中实现 SpringConstraintValidatorFactory 并注入应用程序上下文也删除 @AllArgsConstructor 在尝试之前@NoArgsConstructor。

@Import({Validator.class})
@ContextConfiguration(classes = Application.class)
public class Test {
    private LocalValidatorFactoryBean validator;

    @Autowired
    private ConfigurableApplicationContext applicationContext;

    @BeforeEach
    void initialize() {
        SpringConstraintValidatorFactory springConstraintValidatorFactory
                = new SpringConstraintValidatorFactory(
                applicationContext.getAutowireCapableBeanFactory());
        validator = new LocalValidatorFactoryBean();
        validator.setConstraintValidatorFactory(springConstraintValidatorFactory);
        validator.setApplicationContext(applicationContext);
        validator.afterPropertiesSet();
    }
    @Test
    void testValidator(){
        //call the validator here
    }
}

【讨论】:

  • 我目前正在使用@SpringBootTest,是否必须将其换成@ContextConfiguration(classes = MySpringApplicaton.class)。否则,private ConfigurableApplicationContext applicationContext; 的行为完全相同。
【解决方案2】:

伙计,这个问题一团糟。没有解释你想要做什么。你在 repo 上调用方法,那里不存在(你的意思是 CrudRepository 吗?),除非你自己定义它,然后它应该已经显示出来。实体未显示。实际问题不指向...

看来您的 SampleRepository 没有自动装配。很可能是因为你的

public LocalValidatorFactoryBean localValidatorFactoryBean(ConstraintValidatorFactory validatorFactory)

只需设置一个默认的ConstraintValidatorFactoryImpl 类,它只是使用无参数构造函数通过反射创建验证器实例,并且不会发生注入。你能验证一下是不是这样吗?如果是这样,您需要找到一些进行注入的策略(可能是 SpringConstraintValidatorFactory 吗?)并设置这个,即。尝试声明 SpringConstraintValidatorFactory bean 并使用该 bean 设置 LocalValidatorFactoryBean。

但这只是一个猜测,我对这个问题理解不够。

【讨论】:

  • @org.springframework.stereotype.Repository public interface SampleRepository extends Repository&lt;SampleEntity, String&gt; @Test void trackingBugCausedByValidatorNotPortable() { var entity = new SampleEntity(); entity.setId("an id"); repo.save(entity); repo.delete(entity); assertTrue(repo.existsById("something")); }existsById() 行中抛出错误javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.。我希望这会有所帮助。
  • IIUC 你在那里得到了 NPE,并且 existsById 不会抛出 NPE。所以你的回购在那里是空的。这意味着它没有被注入。哪个 ConstraintValidatorFactory 被注入到名为 localValidatorFactoryBean 的配置方法中?
  • 我选择哪个。我尝试将我自己的工厂注入localValidatorFactoryBean(见问题)并覆盖ConstraintValidatorFactory,但都不起作用。我将通过我的跟踪测试更新问题,看看我是否可以引导您完成整个过程。
  • 那么用的是哪一个? ConstraintValidatorFactory 验证器工厂中注入了什么?我的意思是您将其设置为bean.setConstraintValidatorFactory(validatorFactory);validatorFactory 是什么?它是什么类的实例?
  • ConstraintValidatorFactory 的自定义构建实例
猜你喜欢
  • 1970-01-01
  • 2019-02-25
  • 2017-04-27
  • 2017-04-19
  • 1970-01-01
  • 2018-08-20
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多