This example is a bit contrived; I've simplified it to remove extraneous details and to focus on the problem I am having. I have a validator that looks like this:
@Component
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
@Autowired
UsernameService usernameService;
@Override
public void initialize(UniqueUsername uniqueUsername) {
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
return !usernameService.exists(s);
}
}
I call the validator from my controller like this:
@RequestMapping
public void checkUsername(Model model, User user) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> constraintViolations = validator.validateProperty(user, "username");
model.addAttribute("error", constraintViolations.size() > 0);
}
However, I keep getting an NullPointerException
exception. I added a breakpoint in my validator and saw that usernameService
was null
. Why isn't it getting autowired? Initially I thought it was because I hadn't annotated the validator with @Component
, but I still have the same problem even after annotating it. The UsernameService
class has already been annotated with @Service
and I can verify that its constructor is getting called.
I am new to Spring, so I'm not even sure if it is alright to wire a service into a validator. What am I doing wrong?
In Spring, you need to obtain
ValidatorFactory
(orValidator
itself) viaLocalValidatorFactoryBean
instead ofValidation.buildDefaultValidatorFactory()
, as described in the reference.-
EDIT: But perhaps the better way to do it is to use Spring MVC's automatic validation with
@Valid
annotation:This also requires
<mvc:annotation-driven/>
in the config.Instead of creating a new validator, you have to autowire or inject it to controller. The
NPE
from the service not being injected as your validator is not being created/managed by spring.