As seen in this Baeldung example, it is possible to write plain old javax.validation objects and Spring is able to manage them. For example, it is possible to perform field injection in a validator without annotating it as a component:
public class MyValidator implements ConstraintValidator<MyAnnotation, String> {
@Autowired
private MyBean bean;
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return bean.getValidElements().contains(value);
}
}
Yet, MyValidator is not a Spring bean: a beanFactory.getBean(MyValidator.class) (or an applicationContext.getBean(MyValidator.class)) will throw
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my.package.MyValidator' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
This can be fixed adding a @Component annotation on MyValidator, but maybe it is cleaner to not annotate them as components: I have several validators that extends a common abstract class, so I'm planning to annotate that class in this way, but I feel it would be more maintenable to just have a beanFactory.getBean(MyValidator.class) of sorts and keep each validator as plain as possible.
Is there a way to retrieve the validators without annotating them as components, as Spring already manage them somehow? A minimal example can be found here.
The Validation API has support to have dependencies injected into the
ConstraintValidatorbased on the annotation metadata. This has nothing to do with Spring but is supported by the Validation API.To support the injection there is the
[javax.jakarta].validation.ConstraintValidatorFactoryinterface. Spring has 2 implementations for this, but commonly used is theSpringWebConstraintValidatorFactory.What happens is that when validation is requested based on the annotations present the Validation API will call
ConstraintValidatorFactory.createto get an instance of the needed validator(s).Spring will construct an instance on the fly and if there are
@Autowiredor@Injectfields (or constructors), Spring will happily inject the dependencies.The created validators are NOT Spring Managed beans. The lifecycle of those validators is totally in control of the Validation API and not Spring. As such they are also not retrievable from the
ApplicationContext, unless you explictly make them beans.To make them beans you can do 1 of several things.
@Component.@Configurationclass with@Beanmethods@ComponentScan(includeFilter = @Filter(type=ASSIGNABLE_TYPE, classes = ConstraintValidator.class).Either will (or can) result in your validators being Spring managed.