If you are using a HibernateValidator, you must say to use the HibernateValidator class
By exploring javadoc LocalValidatorFactoryBean
When you talk to an instance of this bean via the Spring or JSR-303 Validator interfaces, you will access the default validator of the base ValidatorFactory. This is very convenient because you do not need to make another call to the factory, assuming that you will almost always use the default validator. It can also be entered directly into any target dependency type Validator!
So you should use the setProviderClass method to indicate which class to use
Here is what I did (I am using annotation based configuration, but it is the same):
Webmvcconfig
@Override public Validator getValidator() { LocalValidatorFactoryBean lvfb = new LocalValidatorFactoryBean(); lvfb.setProviderClass(HibernateValidator.class); return lvfb; }
Model
@Entity @Table(name = "CANDIDATO") public class Candidato extends AbstractModel { private static final long serialVersionUID = -5648780121365553697L; . . . private String corsoLaurea; . . . @Column(name="CORSO_LAUREA", nullable=true) @NotEmpty public String getCorsoLaurea() { return corsoLaurea; } }
controller method
@RequestMapping(method = { RequestMethod.PUT }, value = { "/salvaModificheCandidato" }) public ResponseEntity<BaseResponse<String>> modificaCandidato(@RequestBody @Valid ModificaCandidatoDto dto, BindingResult bindResult) throws Exception { BaseResponse<String> result = null; HttpStatus status = null; try { this.candidatoSvc.modificaCandidato(dto); result = new BaseResponse<String>(); status = HttpStatus.OK; result.setDescrizioneOperazione("Aggiornamento candidato terminato correttamente"); result.setEsitoOperazione(status.value()); result.setPayload(Collections.EMPTY_LIST); } catch (Exception e) { result = new BaseResponse<String>(); status = HttpStatus.INTERNAL_SERVER_ERROR; String message = "Errore nella modifica del candicato con ID "+dto.getIdCandidato()+"; "+e.getMessage(); logger.error(message, e); result.setDescrizioneOperazione(message); result.setEsitoOperazione(status.value()); } return new ResponseEntity<BaseResponse<String>>(result, status); }
In this configuration, I detect bindinresult errors for DTO and Model
I hope this can be useful
SEPARATE PART
I saw that your problem is that bindresult is not empty when you try to save your object; So I changed the code
No model changes (I used the NotEmpty annotation to verify hibernation)
I changed my maintenance method as follows:
@Override @Transactional(transactionManager = "hibTx", rollbackFor = CandidatiDbException.class, readOnly = false) public void modificaCandidato(ModificaCandidatoDto dto, BindingResult brErrors) throws CandidatiDbException { try { dao.modificaCandidato(dto, brErrors); } catch (Exception e) { String message = "Errore nella modifica del candidato con ID "+dto.getIdCandidato()+"; "+e.getMessage(); logger.error(message, e); throw new CandidatiDbException(message); } }
As you can see, I passed the BindingResult object BindingResult method
Then I changed my DAO impl like this:
public class CandidatoDaoImpl<T> implements ICandidatoDao<T> { @Autowired @Qualifier("candValidator") Validator validator; public void modificaCandidato(ModificaCandidatoDto dto, BindingResult brErrors) { Session sessione = getSession(); sessione.setCacheMode(CacheMode.IGNORE); Candidato candidato = sessione.load(Candidato.class, dto.getIdCandidato()); . . . validator.validate(candidato, brErrors); if( !brErrors.hasErrors() ) { sessione.saveOrUpdate(candidato); } } }
Finally, I updated my WebMvcConfig as follows:
@Configuration @EnableWebMvc @Import(SharedSpringConfig.class) @PropertySource( value={"classpath:configuration.properties"}, encoding="UTF-8", ignoreResourceNotFound=false) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Bean(name="candValidator") public Validator validator() { LocalValidatorFactoryBean lvfb = new LocalValidatorFactoryBean(); lvfb.setProviderClass(HibernateValidator.class); return lvfb; } @Override public Validator getValidator() { return validator(); } }
That way, when I have some error in the object that I want to save, I have a BindingResult object that is not empty and no exception is thrown
I hope this can be useful
Angelo