2010-08-27 13 views
9

Questo esempio è un po 'forzato; L'ho semplificato per rimuovere dettagli estranei e per concentrarmi sul problema che sto riscontrando. Ho un validatore che assomiglia a questo:Autowiring di un servizio in un validatore

@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 in questo modo:

@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, continuo a ricevere un'eccezione NullPointerException. Ho aggiunto un punto di interruzione nel mio validatore e ho visto che usernameService era null. Perché non viene avviato automaticamente? Inizialmente pensavo che fosse perché non avevo annotato il validatore con @Component, ma ho ancora lo stesso problema anche dopo averlo annotato. La classe UsernameService è già stata annotata con @Service e posso verificare che il suo costruttore venga chiamato.

Sono nuovo per la primavera, quindi non sono nemmeno sicuro se è giusto collegare un servizio a un validatore. Che cosa sto facendo di sbagliato?

risposta

11

In primavera, è necessario ottenere ValidatorFactory (o Validator stesso) tramite LocalValidatorFactoryBean invece di Validation.buildDefaultValidatorFactory(), come descritto 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: Ma forse il modo migliore per farlo è quello di utilizzare la convalida automatica di Spring MVC con @Valid annotazione:

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

Questo richiede anche <mvc:annotation-driven/> in la configurazione.

+0

Grazie mille! Questo è esattamente quello che stavo cercando. Stavo esaminando la documentazione di riferimento, ma stavo cercando cose come "autowiring services in constraints". Grazie ancora! –

+0

Mi piace la modifica con @Valid. Vorrei poter invocare più di una volta :) –

+0

Grazie mille, la tua risposta mi ha aiutato a risparmiare tempo! –

0

Invece di creare un nuovo validatore, è necessario autowire o iniettarlo al controller. Il NPE dal servizio non viene iniettato poiché il vostro validatore non viene creato/gestito da primavera.

+0

Se autowire direttamente il validatore, ho bisogno del 'ConstraintValidatorContext' per chiamare' isValid'. Come ottengo quello? Sembra anche un po 'imbarazzante per me. C'è un modo migliore per fare ciò che sto cercando di fare? –

Problemi correlati