Валидатор Hibernate в Spring Boot с использованием другого ConstraintValidatorManager - PullRequest
1 голос
/ 11 июня 2019

Я столкнулся с проблемой, которая была упомянута ранее при Spring Boot vs. Hibernate Validation, когда не работает автоматическое подключение зависимостей внутри пользовательских Constraint Validators. Исходя из моей собственной отладки, я заметил, что когда происходит проверка на уровне объекта, Hibernate загружает другой ConstraintValidatorManager по сравнению с тем, когда Hibernate выполняет проверку bean-компонента для отправки формы. Последний работает нормально, первый приводит к тому, что зависимости пользовательского Constraint Validator будут нулевыми. Похоже, что Hibernate загружает один менеджер из корневого контекста и один из контекста сервлета. Это объяснило бы, что Hibernate не знает о существовании зависимостей, автоматически связанных в пользовательском Constraint Validator. Однако, если это правда, я не понимаю, что происходит, и как заставить Hibernate / JPA узнать о контексте Spring и его компонентах.

Я надеюсь, что кто-то может указать мне правильное направление? Я перепробовал все приведенные ниже ответы и многое другое (например, различные версии библиотек, методы настройки, загрузка статических бинов через класс utils и т. Д.):

Внедрить репозиторий внутри ConstraintValidator с Spring 4 и конфигурацией интерполяции сообщений

Autowired дает нулевое значение в валидаторе Custom Constraint

Также я несколько раз без особого везения читал Справочное руководство по Spring Boot. Есть несколько случаев, в которых упоминается, что их валидация Hibernate работает нормально как для регулярных отправок bean-компонентов, так и во время сохранения сущностей. К сожалению, я не могу получить их точную (Java) конфигурацию, которую они использовали, но кажется, что они используют конфигурацию по умолчанию. Я начинаю задумываться, не является ли это конкретной проблемой Spring Boot (хотя указано, что комбинация Spring Validation и Hibernate Validation должна работать «из коробки»).

Добавление чего-либо подобного приведенному ниже bean-компоненту не решает проблему (фабрикой по умолчанию является SpringConstraintValidatorFactory ofcourse):

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

Также не включено определение бина для валидатора Hibernate как таковое:

Autowired дает нулевое значение в валидаторе Custom Constraint

Существует много разных способов загрузки и внедрения желаемого 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'
}

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Что касается исправления, просто для того, чтобы подвести итог более обширному / интегрированному ответу для других, которые имели / имели дело с такого рода проблемами, моя конфигурация теперь содержит все эти компоненты:

@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)
    };
}

Пример добавления групп проверки гибернации для раздельной проверки различных событий жизненного цикла (например, компонента и объекта) см. В Проверка гибернации только при сохранении (вставке)

0 голосов
/ 12 июня 2019

Есть способ указать Hibernate использовать тот же валидатор, установив javax.persistence.validation.factory

@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);
            }
        };
    }
}

Таким образом, все работает нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...