【问题标题】:Spring 3.1 Autowiring does not work inside custom constraint validatorSpring 3.1 自动装配在自定义约束验证器中不起作用
【发布时间】:2012-09-22 11:32:13
【问题描述】:

我在自定义约束验证器中遇到 bean 自动装配问题。没有使用 Spring 的 LocalValidatorFactoryBean 给出约束验证器实例。 JSR-303 提供程序是 hibernate-validator 4.2.0.Final。

Spring 配置摘录:

<!-- JSR 303 validation -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/> 

自定义约束验证器:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;

import com.model.Subject;
import com.services.SomeTypeService;

public class ReadOnlyValidator implements ConstraintValidator<ReadOnly, String> {

@Autowired
private SomeTypeService someTypeService;

@Override
public void initialize(ReadOnly constraintAnnotation) { }

@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
    try {
         if (null != type) {
                        return !someTypeService.isReadonly(type);
                     }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return false;
}
}

注释:

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = ReadOnlyValidator.class)
@Documented
public @interface ReadOnly {
String message() default "{constraints.subjecttype.readonly}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}

一些服务:

 @Validated
 public interface SomeService {
    ...
    public void updateType(@ReadOnly String type) throws SomeException;
    ...
 }

SomeServiceImpl :

 @Service
 public class SomeServiceImpl implements SomeService {
  ...
    public void updateType(String type) throws SomeException {
     // do something
    }
  ...
 }

SomeTypeService 是另一个不依赖于 SomeService 的 @Service 注释 bean ...

问题是我得到一个 NPE,因为自动装配不起作用;其他人正在管理自定义验证器实例,而不是 Spring ...

提前感谢任何类型的建议。

【问题讨论】:

  • Question Claudiu - 你有两个不同的应用程序上下文 - 一个通过 ContextLoaderListener 声明,一个通过 DispatcherServlet,因为你在服务方法级别有@validated,你可能需要在根中声明一个 LocalValidatorFactoryBean网络应用程序上下文也是?
  • 嗯,我确实发现了一些与 LocalValidatorFactoryBean 实例数量相关的异常情况。我在“问题”描述中给出的声明位于 service-content.xml => 这是一个实例。使用 => 时会自动创建另一个实例 => 我们对拥有根 Web 应用程序是正确的。
  • 在验证只创建了一个 LocalValidatorFactoryBean 实例后,我开始验证创建了多少个 ReadOnlyValidator 实例。使用 jmap -histo:live | grep "ReadOnlyValidator",我注意到只创建了一个实例,但仅在第一次调用 updateType 服务方法时才创建,而不是在初始化 LocalValidatorFactBean 时。我认为休眠验证引擎只是创建自己的约束验证器实例。我将如何“强制” LocalValidatorFactoryBean 管理 ReadOnlyValidator 实例以便可以使用 bean 接线?

标签: spring validation customvalidator hibernate-validator


【解决方案1】:

Tito,请检查您是否可以在 Java 配置中使用类似以下的内容:

@Configuration
public class SampleConfig {
  ...

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

  @Bean
  public MethodValidationPostProcessor mvpp() {
    MethodValidationPostProcessor mvpp = new MethodValidationPostProcessor();
    mvpp.setValidator(validator());

    return mvpp;
  }

  ...
}

要在不同的配置 bean 中重用验证器 bean,您可以使用 @Import 注释。

【讨论】:

    【解决方案2】:

    发现问题。 MethodValidationPostProcessor 和 mvc:annotation-driven 声明必须使用相同的“验证器”bean 引用:

    service-context.xml

    <!-- JSR 303 validation -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
    <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
        <property name="validator" ref="validator"/>
    </bean>
        ...
    

    dispatcher-servlet.xml

    ...
    <mvc:annotation-driven validator="validator" />
    ...
    

    【讨论】:

    • Claudiu,这是否意味着我们需要向 MethodValidationPostProcessor 注册每个新的验证器。你知道如何使用 Java Config 来实现它吗?我遇到了同样的问题。唯一的区别是我正在自动装配一个接口,并且我使用的是 Java Config 而不是 xml。
    • 我不得不将验证器“注入”到 MethodValidationPostProcessor 中。
    • 如果在 dispatcher-servlet.xml 中定义的 bean LocalValidatorFactoryBean 和 MethodValidationPostProcessor @Validated 将不起作用。
    猜你喜欢
    • 2018-01-29
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多