java Autowired 在自定义约束验证器中给出 Null 值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37958145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Autowired gives Null value in Custom Constraint validator
提问by Nick Div
I am totally new to Spring and I have looked in to a few answers on SO for the asked problem. Here are the links:
我对 Spring 完全陌生,我已经查看了一些关于 SO 的问题的答案。以下是链接:
Spring 3.1 Autowiring does not work inside custom constraint validator
Autowiring a service into a validator
Autowired Repository is Null in Custom Constraint Validator
I have a Spring project in which I want to use Hibernate Validator for an object validation. Based on what I read online and a few forums I tried to inject validator as follows:
我有一个 Spring 项目,我想在其中使用 Hibernate Validator 进行对象验证。根据我在网上阅读的内容和一些论坛,我尝试按如下方式注入验证器:
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
But wherever I was using
但无论我在哪里使用
@Autowired
Validator validator;
It was taking Spring's validator implementation instead of the Hibernate's validator. I couldn't figure out how to exactly inject Hibernate validator and simply Autowire it across other classes so I used a cheap trick, now my Java Config looks like this
它采用 Spring 的验证器实现而不是 Hibernate 的验证器。我无法弄清楚如何准确地注入 Hibernate 验证器并简单地将它自动连接到其他类,所以我使用了一个便宜的技巧,现在我的 Java 配置看起来像这样
@Bean
public Validator validator() {
// ValidatorImpl is Hibernate's implementation of the Validator
return new ValidatorImpl();
}
(I would really appreciate if someone can actually point me into the right direction on how to avoid getting Hibernate Validator in this Hacky way)
(如果有人能够真正为我指明如何避免以这种 Hacky 方式获取 Hibernate Validator 的正确方向,我将不胜感激)
But lets come to the main issue here:
但是让我们来看看这里的主要问题:
Here is custom validation definition
这是自定义验证定义
@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = EmployeeValidator.class)
@Documented
public @interface EmployeeValidation {
String message() default "{constraints.employeeConstraints}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}
My Custom Validator
我的自定义验证器
public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {
@Autowired
private EmployeeService employeeService;
@Override
public void initialize(EmployeeValidation constraintAnnotation) {
//do Something
}
@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
return false;
}
}
In the above Custom Constraint Validator I get the employeeService null. I know that any implementations of ConstraintValidator are not instantiated when Spring is starting up but I thought adding the ValidatorImpl() will actually fix that. But it didn't.
在上面的自定义约束验证器中,我得到了 employeeService 为空。我知道在 Spring 启动时没有实例化 ConstraintValidator 的任何实现,但我认为添加 ValidatorImpl() 实际上会解决这个问题。但它没有。
Now I am stuck with a really hacky workaround and I do not want to continue with a code like that. Can someone please help me with my situation.
现在我陷入了一个非常棘手的解决方法,我不想继续使用这样的代码。有人可以帮助我解决我的情况。
P.S. These are my imports in the Java Config file:
PS 这些是我在 Java 配置文件中的导入:
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
回答by Nick Div
I hope the solution will help someone:
我希望该解决方案能帮助某人:
@Bean
public Validator validator () {
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
Initializing the validator with SpringConstraintValidatorFactory
so that injection works and providing the validator implementation to be Hibernate.class works in the following manner:
初始化验证器SpringConstraintValidatorFactory
以便注入工作并提供验证器实现为 Hibernate.class 以以下方式工作:
- Your objects will be validated by the library of your choice
- Your custom validators will be able to use Spring's functionality while having validation to be executed by Hibernate.
- 您的对象将由您选择的库进行验证
- 您的自定义验证器将能够使用 Spring 的功能,同时让 Hibernate 执行验证。
How it works:
Hibernate's ConstraintValidatorFactory
does not initialize any ConstraintValidators
unless they are called but SpringConstraintValidatorFactory
does by giving AutowireCapableBeanFactory
to it.
它是如何工作的:除非被调用,否则HibernateConstraintValidatorFactory
不会初始化任何内容ConstraintValidators
,而是SpringConstraintValidatorFactory
通过给予AutowireCapableBeanFactory
它来初始化。
EDIT
编辑
As mentioned in one of the comments by @shabyasaschi To inject autowireCapableBeanFactory
you can change the method signature as:
正如@shabyasaschi 的评论之一所述,要注入autowireCapableBeanFactory
您可以将方法签名更改为:
Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {
or add getter and setter for it in the config file as follows:
或在配置文件中为其添加 getter 和 setter,如下所示:
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
return autowireCapableBeanFactory;
}
public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory) {
this.autowireCapableBeanFactory = autowireCapableBeanFactory;
}
回答by Gunnar
In your bean definition
在你的 bean 定义中
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
What's the type of Validator
in the method definition? You should make sure it returns javax.validation.Validator
, notValidator
from Spring.
Validator
方法定义中的类型是什么?您应该确保它返回javax.validation.Validator
,而不是Validator
从 Spring返回。
Letting Spring bootstrap the validator will it also cause to pass a SpringConstraintValidatorFactory
to Hibernate Validator which will enable dependency injection within constraint validators.
让 Spring 引导验证器也会导致将 a 传递SpringConstraintValidatorFactory
给 Hibernate Validator,这将在约束验证器中启用依赖项注入。
回答by Ricardo Vila
You can fix this with two aproaches:
您可以通过两种方法解决此问题:
Try to inject Services on your validator using Spring.
Initialize it manually overriding Validator's initialize method.
尝试使用 Spring 在您的验证器上注入服务。
手动初始化它,覆盖 Validator 的 initialize 方法。
I had the same problem time ago and finally i decided to use second option avoiding tons of problems.
前一段时间我遇到了同样的问题,最后我决定使用第二个选项来避免大量问题。
As you point you must define one initialize method on your validator and there you can use a ServiceUtils to get the service bean you need:
当您指出时,您必须在验证器上定义一个 initialize 方法,然后您可以使用 ServiceUtils 来获取您需要的服务 bean:
@Autowired
private EmployeeService employeeService;
@Override
public void initialize(EmployeeValidation constraintAnnotation) {
//Use an utility service to get Spring beans
employeeService = ServiceUtils.getEmployeeService();
}
And ServiceUtils is a normal Spring bean with a static reference to itself used in the static methods.
而 ServiceUtils 是一个普通的 Spring bean,在静态方法中使用了对自身的静态引用。
@Component
public class ServiceUtils {
private static ServiceUtils instance;
@Autowired
private EmployeeService employeeService;
/* Post constructor */
@PostConstruct
public void fillInstance() {
instance = this;
}
/*static methods */
public static EmployeeService getEmployeeService) {
return instance.employeeService;
}
}
So you are using Spring to inject the services you need but not in the usual way. Hope this helps.
所以您正在使用 Spring 注入您需要的服务,但不是以通常的方式。希望这可以帮助。
回答by user4441649
private XXXService xxxService = SpringContextHolder.getBean(XXXService.class);
回答by ykembayev
Thats worked for me. For guys who search at now
那对我有用。对于现在搜索的人
public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {
private EmployeeService employeeService;
public EmployeeValidator(EmployeeService employeeService){
this.employeeService = employeeService;
}
...
}