繁体   English   中英

使用不同的ConstraintValidatorManager的Spring Boot中的Hibernate Validator

[英]Hibernate Validator in Spring Boot using different ConstraintValidatorManager

我遇到的是Spring Boot与Hibernate Validation之前提到的问题,其中自定义约束验证器中的依赖项自动装配无法正常工作。 通过我自己的调试,我注意到,当进行实体级验证时,与Hibernate对表单提交执行Bean验证时相比,Hibernate加载了一个不同的ConstraintValidatorManager。 后者工作正常,前者导致自定义约束验证器的相关性为空。 似乎Hibernate正在从根上下文中加载一个管理器,并从servlet上下文中加载一个管理器。 这将解释Hibernate不了解自定义约束验证器中自动关联的依赖项的存在。 但是,如果这是真的,我将不知道发生了什么,或者如何使Hibernate / JPA知道Spring上下文及其bean。

我希望有人可以指出正确的方向吗? 我已经尝试了以下所有答案,以及更多其他答案(例如,不同的库版本,配置方法,通过utils类加载静态bean等):

使用Spring 4和消息插值配置在ConstraintValidator中注入存储库

Autowired在“自定义约束”验证器中给出Null值

另外,我已经多次专门浏览过Spring Boot参考指南,但运气不佳。 有几种情况提到它们的Hibernate验证在常规bean提交以及实体持久期间均能正常工作。 不幸的是,我似乎无法检索他们使用的确切(Java)配置,但似乎他们正在使用默认配置。 我开始怀疑这是否是特定的Spring Boot问题(尽管已经指出,Spring Validation和Hibernate Validation的组合应该可以立即使用)。

在bean下面添加任何东西都不能解决问题(默认工厂为Course的SpringConstraintValidatorFactory):

@Bean
public LocalValidatorFactoryBean validator()
{
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource());
    return bean;
}

也没有为Hibernate验证器包括bean定义,例如:

Autowired在“自定义约束”验证器中给出Null值

加载和注入所需的bean有很多不同的方法,但是如果Hibernate根本不知道在上下文中加载的bean(因为它使用的是不同的上下文?),该如何进行?

提前致谢。

更新:Gradle文件

buildscript {
    ext {
        springBootVersion = '2.1.5.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = '<hidden>'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web')
    implementation('org.springframework.boot:spring-boot-starter-tomcat:2.1.5.RELEASE')

    implementation('org.springframework.boot:spring-boot-starter-thymeleaf')
    implementation('org.springframework.boot:spring-boot-starter-security')
    implementation('org.springframework.boot:spring-boot-starter-data-jpa')
    implementation('org.springframework.boot:spring-boot-starter-mail')
    implementation('org.springframework.session:spring-session-core')

    annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')

    implementation('org.postgresql:postgresql')

    // https://mvnrepository.com/artifact/org.jboss.aerogear/aerogear-otp-java
    implementation('org.jboss.aerogear:aerogear-otp-java:1.0.0')

    implementation('com.github.mkopylec:recaptcha-spring-boot-starter:2.2.0')
    implementation('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.0.5')
    implementation('org.thymeleaf.extras:thymeleaf-extras-springsecurity3:3.0.4.RELEASE')

    implementation('javax.enterprise:cdi-api:2.0')

    runtimeOnly('org.springframework.boot:spring-boot-devtools')

    testImplementation('org.springframework.boot:spring-boot-starter-test')
    testImplementation('org.springframework.security:spring-security-test')
    testImplementation 'org.mockito:mockito-core:2.27.0'
}

通过设置javax.persistence.validation.factory可以告诉Hibernate使用相同的验证器。

@Configuration
@Lazy
class SpringValidatorConfiguration {

    @Bean
    @Lazy
    public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(final Validator validator) {
        return new HibernatePropertiesCustomizer() {

            @Override
            public void customize(Map<String, Object> hibernateProperties) {
                hibernateProperties.put("javax.persistence.validation.factory", validator);
            }
        };
    }
}

这样,一切正常。

关于此修复程序,仅是为了总结正在/正在处理此类问题的其他人的更广泛/综合的答案,我的配置现在包含所有这些bean:

@Bean
public LocalValidatorFactoryBean validator()
{
    LocalValidatorFactoryBean validatorFactory = new LocalValidatorFactoryBean();
    validatorFactory.setValidationMessageSource(messageSource());
    return validatorFactory;
}

@Bean
public MessageSource messageSource()
{
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasename("classpath:messages");
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() 
{
    MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
    methodValidationPostProcessor.setValidator(validator());
    return methodValidationPostProcessor;
}

@Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer()
{
    return properties ->
    {
        properties.put("javax.persistence.validation.factory", validator());
        // Add more properties here such as validation groups (see comment for SO example)
    };
}

有关添加休眠验证组以梳理不同生命周期事件(例如Bean与实体)的验证的示例,请参阅仅保存(插入)时进行的休眠验证

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM