Autowiring un service dans un validateur
-
01-10-2019 - |
Question
Cet exemple est un peu controuvé; Je l'ai simplifié pour éliminer les détails superflus et de se concentrer sur le problème que j'ai. J'ai un validateur qui ressemble à ceci:
@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);
}
}
J'appelle le validateur de mon contrôleur comme ceci:
@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);
}
Cependant, je continue à obtenir une exception NullPointerException
. J'ai ajouté un point d'arrêt dans mon validateur et a vu que usernameService
était null
. Pourquoi est-ce pas s'autowired? Au début, je pensais que c'était parce que je ne l'avais pas annoté le validateur avec @Component
, mais je dois toujours le même problème, même après l'annotant. La classe UsernameService
a déjà été annoté avec @Service
et je peux vérifier que son constructeur est appelé se.
Je suis nouveau au printemps, donc je ne suis même pas sûr si elle est bien câbler un service dans un validateur. Qu'est-ce que je fais mal?
La solution
Au printemps, vous devez obtenir ValidatorFactory
(ou Validator
lui-même) par l'intermédiaire LocalValidatorFactoryBean
au lieu de Validation.buildDefaultValidatorFactory()
, comme décrit dans le de référence.
@Autowired
Validator validator;
@RequestMapping
public void checkUsername(Model model, User user) {
Set<ConstraintViolation<User>> constraintViolations = validator.validateProperty(user, "username");
model.addAttribute("error", constraintViolations.size() > 0);
}
-
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
EDIT: Mais peut-être la meilleure façon de le faire est d'utiliser la validation automatique de Spring MVC avec annotation @Valid
:
@RequestMapping
public void checkUsername(Model model, @Valid User user, BindingResult result) {
if (result.hasErrors()) {
...
}
}
Cela nécessite également <mvc:annotation-driven/>
dans la configuration.
Autres conseils
Au lieu de créer un nouveau validateur, vous devez lier automatiquement ou injecter au contrôleur. Le NPE
du service ne sont pas injectés en tant que votre validateur n'est pas créé / géré par ressort.