2010-08-27 10 views
9

Este ejemplo es un poco artificial; Lo simplifiqué para eliminar detalles extraños y centrarme en el problema que estoy teniendo. Tengo un validador que tiene este aspecto:autowiring un servicio en un validador

@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); 
    } 
} 

que llamo 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 vi que era usernameServicenull. ¿Por qué no se está autoconectando? Inicialmente pensé que era porque no había anotado el validador con @Component, pero todavía tengo el mismo problema incluso después de anotarlo. 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?

Respuesta

11

En primavera, es necesario obtener ValidatorFactory (o Validator sí mismo) a través de LocalValidatorFactoryBean en lugar de Validation.buildDefaultValidatorFactory(), tal como se describe in the reference.

@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 @Valid anotación:

@RequestMapping 
public void checkUsername(Model model, @Valid User user, BindingResult result) { 
    if (result.hasErrors()) { 
     ... 
    } 
} 

Esto también requiere <mvc:annotation-driven/> en la configuración

+0

¡Muchas gracias! Eso es exactamente lo que estaba buscando. Estaba revisando la documentación de referencia, pero estaba buscando cosas como "servicios de autoconexión en restricciones". ¡Gracias de nuevo! –

+0

Me gusta la edición con @Valid. Desearía poder votar más de una vez :) –

+0

¡Muchas gracias, su respuesta me ayudó a ahorrar tiempo! –

0

En lugar de crear un nuevo validador, usted tiene que Autowire o inyectarla al controlador. El NPE del servicio que no se inyectó como su validador no se está creando/administrando para la primavera.

+0

Si Autowire el validador directamente, necesito el '' ConstraintValidatorContext' llamar isValid'. ¿Cómo lo consigo? También me parece un poco tonto. ¿Hay una mejor manera de hacer lo que estoy tratando de hacer? –

Cuestiones relacionadas