使用Spring的JSR-303约束验证器中的依赖注入失败

时间:2014-12-17 13:24:17

标签: spring dependency-injection validation

我遇到与herehere相同的问题但尚未找到解决方案。

所以我的示例测试项目将显示完整的相关配置和代码:

约束注释:

@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FooValidator.class)
public @interface FooValid {

    String message();

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

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

带注释的PoJo:

public class Foo {

    @FooValid(message = "Test failed")
    private Integer test;
    [...]
}

带@Validated的注释服务:

@Service
@Validated
public class FooService {

    private final Test test;

    @Autowired
    public FooService(final Test test) {
        this.test = test;
    }

    public void foo(@Valid final Foo foo) {
        this.test.test(foo);
    }
}

JSR-303 ConstraintValidator:

public class FooValidator implements ConstraintValidator<FooValid, Integer> {

    @Autowired
    private ValidationService validationService;

    @Override
    public void initialize(final FooValid constraintAnnotation) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean isValid(final Integer value, final ConstraintValidatorContext context) {
        // this.validationService is always NULL!
        Assert.notNull(this.validationService, "the validationService must not be null");
        return false;
    }

}

注入验证服务:

@Service
public class ValidationService {

    public void test(final Foo foo) {
        System.out.println(foo);
    }
}

Spring启动应用程序和配置:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(final String[] args) {
        final ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        final FooService service = context.getBean(FooService.class);
        service.foo(new Foo());
    }

    @Bean
    public static LocalValidatorFactoryBean validatorFactory() {
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public static MethodValidationPostProcessor validationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

}
相关的maven pom:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.9.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
    </dependency>
</dependencies>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <start-class>demo.Application</start-class>
    <java.version>1.7</java.version>
</properties>

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

我使用 LocalValidatorFactoryBean 和默认的 SpringConstraintValidatorFactory 。 但是为什么依赖注入不能在ConstraintValidator中工作而 ValidationService 无法自动装配?

顺便说一下,如果我不在服务中使用 @Validated ,请在spring或javax Validator接口的对面注入并手动调用&#34; validator.validate < / EM>&#34;依赖注入将起作用。但我不想手动调用每个服务中的验证方法。

非常感谢您的帮助:)

3 个答案:

答案 0 :(得分:8)

我在Spring Boot环境中遇到了同样的问题,我发现Hibernate的内部实现不是配置Spring的内部实现。当应用程序启动时,调试器在Spring的工厂中占了一席之地,但后来在运行时就有了Hibernate的工厂。经过一些调试后,我得出的结论是 MethodValidationPostProcessor 得到了内部的一个。因此我将其配置如下:

@Bean
public Validator validator() {
    return new LocalValidatorFactoryBean();
}

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

请注意验证器的setter - 它完成了这项工作。

答案 1 :(得分:0)

我有同样的问题。问题出现是因为Hibernate正在寻找并应用验证器而不是Spring。因此,在配置Hibernate时需要将验证模式设置为NONE

@Bean(name="entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
    localContainerEntityManagerFactoryBean(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean lcemfb =
        new LocalContainerEntityManagerFactoryBean();
    lcemfb.setDataSource(dataSource);
    lcemfb.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    lcemfb.setValidationMode(ValidationMode.NONE);
    // Continue configuration...

如果您已经配置了LocalValidationFactoryBean,Spring将选择使用@Component注释的任何验证器并自动装配它们。

答案 2 :(得分:0)

这对我有用。我不得不使用@Inject标记。

    public class FooValidator implements ConstraintValidator<FooValid, Integer> {
        private ValidationService validationService;
        @Inject
        public FooValidator(ValidationService validationService){
            this.validationService = validationService;
        }
        @Override
        public void initialize(final FooValid constraintAnnotation) {
            // TODO Auto-generated method stub
        }
        @Override
        public boolean isValid(final Integer value, final ConstraintValidatorContext context) {
            // this.validationService is always NULL!
            Assert.notNull(this.validationService, "the validationService must not be null");
            return false;
        }

}