[RESOLVIDO] Vraptor + Validation (Erro vindo do Business)

Galera, estou fazendo dois tipos de validação

  1. Validações de tela (campo vazio, validacao de senha, etc…)
  2. Validações de Business ( do banco ) - checar se já existe matrícula para o mesmo aluno, por ex.

O código abaixo funciona! eu gostaria de saber se existe alguma forma melhor de se fazer as validações sem tem que repetir…

validator.addAll(errors);	
validator.onErrorUse(Results.json()).withoutRoot().from(errors).serialize();

no código abaixo.

[code]public void save(final Enrollment enrollment) {

	Enrollment enrollmentToUpdate = enrollmentBusiness.find(enrollment.getId());
	
	List<Message> errors = new Validations(){{
		that(enrollment.getStudent().getId() != null, "validation","studentNotSelected");
    }}.getErrors(ResourceBundle.getBundle("messages"));  
    
    validator.addAll(errors);	
	validator.onErrorUse(Results.json()).withoutRoot().from(errors).serialize();
	
	if (enrollmentToUpdate == null){
		enrollmentToUpdate = new Enrollment();
		enrollmentToUpdate.setCreateDate(new GregorianCalendar());
	}
	enrollmentToUpdate.setUpdateDate(new GregorianCalendar());
	
	enrollmentToUpdate.setDayOfPayment(enrollment.getDayOfPayment());
	enrollmentToUpdate.setGrade(enrollment.getGrade());
	enrollmentToUpdate.setHasAddressProof(enrollment.isHasAddressProof());
	enrollmentToUpdate.setHasBirthCertificate(enrollment.isHasBirthCertificate());
	enrollmentToUpdate.setHasCPFXerox(enrollment.isHasCPFXerox());
	enrollmentToUpdate.setHasFacePhotos(enrollment.isHasFacePhotos());
	enrollmentToUpdate.setHasHealthPlanCard(enrollment.isHasHealthPlanCard());
	enrollmentToUpdate.setHasLastYearSchoolDischarge(enrollment.isHasLastYearSchoolDischarge());
	enrollmentToUpdate.setHasRegistrationNumberXerox(enrollment.isHasRegistrationNumberXerox());
	enrollmentToUpdate.setHasVaccinationCard(enrollment.isHasVaccinationCard());
	enrollmentToUpdate.setMonthOfEnrollment(enrollment.getMonthOfEnrollment());
	enrollmentToUpdate.setShift(enrollment.getShift());
	
	enrollmentToUpdate.setStudent(enrollment.getStudent());
			
	try {
		enrollmentBusiness.saveOrUpdate(enrollmentToUpdate);
	} catch (final InvalidAttributesException e) {
		
		errors.add(new I18nMessage("validation",e.getMessage()));
	}finally{
		validator.addAll(errors);	
		validator.onErrorUse(Results.json()).withoutRoot().from(errors).serialize();
	}
	
	ajaxRedirect("enrollment/list"); 

}[/code]

ao invés de fazer isso, muda para adicionar os erros diretamente no validator, e faça:

validator.onErrorSendBadRequest();

assim o status code da resposta vai ser 400 (assim vc não precisa fazer if lá no javascript) e os erros serão serializados em json (se a requisição veio pedindo json)

Ok,

essa sua sugestão eu já havia entendido mais ainda não tinha aplicado.

mas a questão é que tem erros que são de validação e tem erro que vem no

ai queria saber se tem alguma forma mais limpa de chamar o validador.
para não ter que repetir o mesmo código em cima e em baixo no catch.

Lucas muito obrigado, por toda a força que vc dá ao GUJ.
Vejo vc investindo muito tempo aqui. e vejo várias respostas pertinentes.
Valeu brother!!

adiciona todos os erros no validator. algo assim:

validator.checking(new Validations() {{
   //validações aqui
}});
...
validator.add(<mensagem de erro>);
...
validator.onErrorSendBadRequest();
...

assim, e usando o snapshot que eu te mandei, ele vai fazer do jeito que vc precisa

Eu já fiz isso.

meu código atual.

[code]
public void save(final Enrollment enrollment) {

	Enrollment enrollmentToUpdate = enrollmentBusiness.find(enrollment.getId());
	
	validator.checking(new Validations(){{
		that(enrollment.getStudent().getId() != null, "validation","enrollment.studentNotSelected");
    }});  
    
	validator.onErrorSendBadRequest();
	...
			
	try {
		enrollmentBusiness.saveOrUpdate(enrollmentToUpdate);
	} catch (final InvalidAttributesException e) {
		validator.add(new I18nMessage("validation", e.getMessage()));
		
		validator.onErrorSendBadRequest();
	}
	
	
	result.use(Results.json()).withoutRoot().from("Matrícula salva com sucesso!").serialize();
}[/code]

O detalhe é que tenho que repetir o

Se colocar esse trecho apenas no catch. ele vai salvar o objeto mesmo que tenho erro de validação em cima. sacou?
O que está me incomodando é eu ter que repetir esse código acima.
Tem alguma forma melhor?

então, não tem muito o que fazer, pq qdo vc chama o validator.onErrorXXXX ele já verifica se tem erros e solta uma exception se tiver… vc precisa verificar se tem erros em dois momentos, então tem que chamar essa linha duas vezes mesmo, infelizmente…

na verdade na verdade o jeito que eu faria isso era ignorando esse try…catch no saveOrUpdate. Teoricamente vc deveria evitar esse erro dos InvalidAttributes com as validações anteriores, não é mesmo?

o que vc pode fazer também é usar o BeanValidations para fazer as validações no modelo, e então chamar

validator.validate(objeto); 

antes de invocar o onErrorXXX

Eu checo no bussiness se já existe matrícula (enrrolment) para o aluno.
Acredito que se colocar no controller vou estar quebrando a arquitetura. não acha?

Pensei em colocar um método para validar o objeto no Business. ai eu chamaria no that.

Esse é o method do business:

[code]
public void saveOrUpdate(Enrollment t) throws InvalidAttributesException {
try{
session.beginTransaction();

		Enrollment enroll = findByStudentId(t.getStudent().getId());
		if (t.getId() == null && enroll != null){
			throw new InvalidAttributesException("Já existe matrícula para este usuário");
		}
		
		Student student = studentBusiness.find(t.getStudent().getId());
		t.setStudent(student);
		
		session.saveOrUpdate(t);
		session.getTransaction().commit();
	}catch(InvalidAttributesException e){
		session.getTransaction().rollback();
		throw e;
	}
}[/code]

não sei se estaria quebrando a arquitetura… vc pode fazer algo do tipo, no controller:

if (enrollmentBusiness.existsEnrollmentFor(student)) {
   validator.add(new I18nMessage("student", "enrollment.exists"));
}