Configuring spring validation and hibernate valida

2019-08-30 06:42发布

Problem already solved here but didn't work for me (not same spring boot version i guess) this

Trying to code a custom constraint validator, to check whether account email exists before persisting.

@Email
@NotNull
@NotBlank
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueCompteEmailValidator.class)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface UniqueCompteEmail {

    String message() default "{com.mssmfactory.bacsimulator.uniquecompteemail.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

// --------------------------------------------------------------------------

public class UniqueCompteEmailValidator implements ConstraintValidator<UniqueCompteEmail, String> {

    @Autowired
    private CompteRepository compteRepository;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && this.compteRepository.findByEmail(value) == null;
    }
}

// --------------------------------------------------------------------------

@Configuration
public class OtherConfigurations {

    //----

    @Bean
    public Validator validator(@Autowired AutowireCapableBeanFactory autowireCapableBeanFactory) {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()
                .constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        return validator;
    }
}

// --------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mssmfactory</groupId>
    <artifactId>bacsimulator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bacsimulator</name>
    <description>BAC Simulator</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

My problem is that private CompteRepository compteRepository always contains null, and from my stacktrace, i can see that it's being instanciated by hibernate-validation instead of being instanciated by spring and used by hibernate.

Any idea ?

2条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-08-30 07:27

The issue that you are facing is because the @Autowired annotation is not working for you when you autowire CompteRepository.class.You can autowire components in your validation class but make sure that you use spring to create the validator bean otherwise the bean injection won't work as manually creating validator bean using valdiation factory (Hibernate Validator as reference implentation) does not inject dependencies into ConstraintValidator instances.

So, you cannot use the validator factory to create the validator instance , instead autowire it and everything should work.

@AutoWired
Validator validator;
...

validator.validate(book);
查看更多
地球回转人心会变
3楼-- · 2019-08-30 07:33

Changed hibernate's bean validator factory by this @Component class and now it works so well

@Component
public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {

    private final ObjectProvider<javax.validation.Validator> provider;

    public ValidatorAddingCustomizer(ObjectProvider<javax.validation.Validator> provider) {
        this.provider = provider;
    }

    public void customize(Map<String, Object> hibernateProperties) {
        Validator validator = provider.getIfUnique();

        if (validator != null) {
            hibernateProperties.put("javax.persistence.validation.factory", validator);
        }
    }
}
查看更多
登录 后发表回答