Autowiring un servicio en un validador
-
01-10-2019 - |
Pregunta
Este ejemplo es un poco artificial; He simplificado para eliminar detalles superfluos y centrarse en el problema que estoy teniendo. Tengo un validador que tiene este aspecto:
@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);
}
}
Me llaman el validador de mi controlador de la siguiente manera:
@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);
}
Sin embargo, me siguen dando una excepción NullPointerException
. He añadido un punto de interrupción en mi validador y vio que era usernameService
null
. Por qué no está consiguiendo autowired? Al principio pensé que era porque no había anotado el validador con @Component
, pero todavía tengo el mismo problema, incluso después de la anotación de la misma. La clase UsernameService
ya se ha anotado con @Service
y puedo comprobar que su constructor está recibiendo llamadas.
Soy nuevo en primavera, así que no estoy seguro si está bien para conectar un servicio en un validador. ¿Qué estoy haciendo mal?
Solución
En la primavera, lo que necesita para obtener ValidatorFactory
(o Validator
sí mismo) a través de LocalValidatorFactoryBean
en lugar de Validation.buildDefaultValidatorFactory()
, como se describe en el referencia.
@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: Pero tal vez la mejor manera de hacerlo es utilizar la validación automática de Spring MVC con la anotación @Valid
:
@RequestMapping
public void checkUsername(Model model, @Valid User user, BindingResult result) {
if (result.hasErrors()) {
...
}
}
Esto también requiere <mvc:annotation-driven/>
en el config.
Otros consejos
En lugar de crear un nuevo validador, usted tiene que Autowire o inyectarla al controlador. No se está creando el NPE
del servicio no se está inyectando como su validador / gestionado por la primavera.