Autowiring un servizio in un validatore

Questo esempio è un po ‘ forzato; ho semplificato per rimuovere particolari estranei e mettere a fuoco il problema che sto avendo. Ho un validatore che assomiglia a questo:

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

Io chiamo il validatore dal mio controller come questo:

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

Tuttavia, io continuo a ricevere un NullPointerException eccezione. Ho aggiunto un punto di interruzione nel mio lettore e visto che usernameService era null. Perché non è sempre autowired? Inizialmente ho pensato che era perché non avevo commentato il validatore con @Component, ma ho ancora lo stesso problema anche dopo annotarla. Il UsernameService classe è già stato annotato con @Service e posso verificare che il suo costruttore è sempre chiamato.

Sono nuovo di Primavera, quindi non so nemmeno bene se è a filo di un servizio in un validatore. Che cosa sto facendo di sbagliato?

 

2 Replies
  1. 13

    In Primavera, è necessario ottenere ValidatorFactory (o Validator) tramite LocalValidatorFactoryBean invece di Validation.buildDefaultValidatorFactory(), come descritto in riferimento.

    @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: Ma forse il modo migliore per farlo è quello di utilizzare Spring MVC validazione automatica con @Valid annotazione:

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

    Questo richiede anche <mvc:annotation-driven/> nel config.

    • Grazie mille! Che è esattamente quello che stavo cercando. Stavo attraversando la documentazione di riferimento, ma ero alla ricerca di cose come “autowiring servizi in vincoli”. Grazie ancora!
    • Mi piace la modifica con la @Valido. Vorrei poter dare un voto positivo più di una volta 🙂
    • Grazie mille, la tua risposta mi ha aiutato a risparmiare tempo!
  2. 0

    Invece di creare un nuovo validatore, devi autowire o iniettare ai controller. Il NPE dal servizio non viene iniettato come il validatore non è in fase di creazione/gestito dalla primavera.

    • Se ho autowire il validatore direttamente, ho bisogno di una ConstraintValidatorContext chiamare isValid. Come posso fare per ottenere che? Sembra anche un po ‘ frammentaria per me. C’è un modo migliore per fare quello che sto cercando di fare?

Lascia un commento