[Resolvido] Anotação @Validate na validação de CPF - Stella Caelum

34 respostas
Guevara

Oi pessoal!
Estou seguindo o tutorial (http://stella.caelum.com.br/frameworks-vraptor.html) para validar CPF usando o Stella, mas a anotação @Validate(params = “”) não existe.
Já adicionei os dois jar’s na /lib e dei refresh:
caelum-stella-hibernate-validator-1.2.jar
caelum-stella-core-1.2.jar
Na minha classe está assim:

@CPF
	private String cpf;

Na JSP está:

<label for="cpf">CPF</label>
	<input id="cpf" name="proprietario.cpf" type="text" maxlength="255" /><br />

Mas não valida nada, está gravando com CPF incorreto, achei que poderia ser pela falta do @Validate no método de adicionar o proprietário no Controller:

public void adiciona(final Proprietario proprietario) { 
//codigos
}

Estou usando Hibernate 3.5.1, o jar dele está na /lib.
Abraço!! o/

34 Respostas

G

O Stella somente valida usando Hibernate 3 Validator e Vraptor 2, mas não funciona com o Bean Validator, nem com Vraptor 3 e nem com o Hibernate Validator 4.

A alternativa é você criar um componente para fazer essa validação. O Lavieri fez isso e me mandou o jar, porém eu perdi.

Se você quer fazer validações usando o componente de validação do Vraptor 3 você pode usar uma API que eu andei escrevendo e que está no meu github. Devido a falta de tempo não fiz nenhum build, mas vou ver se faço isso agora mesmo, hehe.

Com essa API basta você anotar seu bean com @CPF, @CNPJ e afins, e quando você persistir o objeto ou chamar no Vrator o validation.validate(meuBean) as anotações serão validados.

http://github.com/garcia-jj/jsr303-br

G

Coloquei um binário lá: http://github.com/garcia-jj/jsr303-br/downloads

Vou aproveitar e atualizar o markdown. :oops:

Guevara

Opa!! Valeu garcia! Não sabia que pro VRaptor 3 não funcionava, uma pena. =/
Já baixei o seu jar aqui, vou ver como funciona e já dou um retorno.
Abraço!

Guevara

Tá mandando configurar o build path…

import com.github.jsr303br.CPF;

@CPF
	private String cpf;

Preciso adicioná-lo lá mesmo estando na /lib?

G

Quando você adiciona um jar dentro do seu projeto, você precisa dar um refresh na workspace (para sincronizar ela com o filesystem) e também precisa adicionar ao projeto.

Quando você tem um Dynamic Web Project e coloca um jar dentro do WEB-INF/lib o Eclipse automagiamente adiciona esse jar ao classpath, caso contrário precisa ser manual.

Guevara

Então, já dei refresh e reiniciei o Tomcat, adicionei o jar ao buildpath e continua mandando configurar lá. =)

G

Vai lá no buildpath então e você se tem algum erro ou warning.

Guevara

Está acusando pra configurar o BuilPath e esta mensagem:

G

Tem que ter o jar do bean validation. No vraptor tem esses jars em lib/optional/validation-api-1.0.0.GA.jar

Guevara

Baixei o jar daqui:
http://repository.jboss.org/maven2/javax/validation/validation-api/1.0.0.GA/
Ai resolveu aquele erro. Anotei na classe @CPF e ao chamar a aplicação pelo browser surgem os erros:

root cause

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'JSR303ValidatorFactory': Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.validation.ValidatorFactory]: : Error creating bean with name 'br.com.caelum.vraptor.validator.ValidatorFactoryCreator': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'validatorFactoryCreator': Invocation of init method failed; nested exception is javax.validation.ValidationException: Unable to find a default provider; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'br.com.caelum.vraptor.validator.ValidatorFactoryCreator': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'validatorFactoryCreator': Invocation of init method failed; nested exception is javax.validation.ValidationException: Unable to find a default provider
root cause

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'br.com.caelum.vraptor.validator.ValidatorFactoryCreator': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'validatorFactoryCreator': Invocation of init method failed; nested exception is javax.validation.ValidationException: Unable to find a default provider
	org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:150)
root cause

javax.validation.ValidationException: Unable to find a default provider
	javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:264)

Têm que fazer algo mais??
Abraço!

G

O ideal é pegar os jars que tem no próprio vraptor.

Se você não está em um appserver com JEE6 você precisa também do Hibernate Validator 4x (tem tudo no vraptor/lib)

Guevara

Vou baixar o último VRaptor de novo, pq no que eu tenho não existe esse jar dentro da /lib/optional.
guenta ai…

Guevara

Agora sim, preenchi o form e tenho este erro agora:

root cause

javax.validation.ConstraintViolationException: validation failed for classes [br.com.imobiliaria.bean.Proprietario] during persist time for groups [javax.validation.groups.Default, ]
	org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:132)
	org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:71)
	org.hibernate.action.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:159)
	org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:65)
	org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)

Preciso anotar o método do Controller com @ Valid?
import javax.validation.Valid;

Abraço!

Guevara

Consegui inserir um proprietario com a anotação:

@CPF(formatted=true, message="erro no cpf")
	private String cpf;

Mas como faço pra essa msg aparecer na jsp? É assim que usa essa anotação pra validar?

G

Madrugando, é? Hehehe.

Guevara, basta você anotar a classe POJO com as tuas constraints tanto com as do Bean Validation como dessa API que te passei. Após você anotar a classe o próximo passo é injetar o objeto Validation do Vraptor no seu controller. Nele há um método chamado Validation.validate, que valida teus beans a partir das anotações que você usou.

@Resource
public class CustomerController {

    private final Validator validator;

    public CustomerController(Validator validator) {
        this.validator = validator;
    }

    public void store(CustomerDetails customer) {
        validator.validate(customer);
        validator.onErrorForwardTo(this).edit(customer.getId());
    }
}

A validação é devolvida para você dentro do objeto errors que fica acesível do JSP como ${errors}, esse que você já deve conhecer, que é o padrão do Vraptor. Esse objeto na verdade é um map sendo que o key é o campo com erro e value é a mensagem de validação.

<c:if test="${not empty errors}">
	Erros de validação: <br />
	<c:forEach items="${errors}" var="e">
		${e.category} - ${e.message} <br />
	</c:forEach>
</c:if>

Abraços

Guevara

Opa!
Agora sim! :smiley:
Foi só colocar o validator.validate(proprietario) que funcionou. \o/
O legal é que dá pra validar E-Mail, CEP e CNPJ também.
Valeu Garcia!
Abraço!!

obs: o Java tá dominando as madrugadas. :lol:

Guevara

Opa, beleza??
Onde posso achar a documentação das anotações?
Preciso configurar isto direito pq agora não consigo inserir os dados com o que eu tenho anotado:

@CPF(formatted=true, message="CPF inválido, digite novamente")
	private String cpf;
	@Telefone(format="####-####", message="Telefone incorreto, digite novamente")
	private String telefone;
	@Telefone(format="####-####", message="Celular incorreto, digite novamente")

Stacktrace:

21:21:56,660 DEBUG [OgnlParametersProvider] Applying proprietario.email with [[email removido]]
21:21:56,679 DEBUG [OgnlParametersProvider] Applying proprietario.cpf with [[CPF removido]]
21:21:56,680 DEBUG [OgnlParametersProvider] Applying proprietario.telefone with [7898-8555]
21:21:56,681 DEBUG [OgnlParametersProvider] Applying proprietario.celular with [8855-1223]
21:21:56,682 DEBUG [OgnlParametersProvider] Applying proprietario.nome with [Elaine]
21:21:56,683 DEBUG [OgnlParametersProvider] Applying proprietario.idProprietario with [4]
21:21:56,685 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ProprietarioController.altera(Proprietario) as [proprietario]
21:21:56,685 DEBUG [ParametersInstantiatorInterceptor] Parameter values for [DefaultResourceMethod: ProprietarioController.alteraProprietarioController.altera(Proprietario)] are [br.com.imobiliaria.bean.Proprietario@19de6c]
21:21:56,713 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ExecuteMethodInterceptor
21:21:56,714 DEBUG [ExecuteMethodInterceptor] Invoking ProprietarioController.altera(Proprietario)
21:21:56,765 DEBUG [JSR303Validator     ] there are 3 violations at bean br.com.imobiliaria.bean.Proprietario@19de6c.
21:21:56,768 DEBUG [JSR303Validator     ] added message Celular incorreto, digite novamente to validation of bean br.com.imobiliaria.bean.Proprietario@19de6c
21:21:56,769 DEBUG [JSR303Validator     ] added message Telefone incorreto, digite novamente to validation of bean br.com.imobiliaria.bean.Proprietario@19de6c
21:21:56,769 DEBUG [JSR303Validator     ] added message CPF inválido, digite novamente to validation of bean br.com.imobiliaria.bean.Proprietario@19de6c
21:21:56,769 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ProprietarioController.altera(Proprietario) as [proprietario]
21:21:56,979 DEBUG [DefaultLogicResult  ] redirecting to class ProprietarioController
21:21:57,013 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ProprietarioController.edita(Long) as [idProprietario]
21:21:57,014 DEBUG [DefaultLogicResult  ] redirecting to /imobiliaria/proprietario/edita
21:21:57,015 DEBUG [VRaptor             ] VRaptor ended the request

Esse “format” que eu não sei se está certo.
Abraço!

Guevara

É só o Garcia que têm a documentação desse js303-br.jar?
Abraço!!

G

Oi Guevara. Esse projeto é um projeto pessoal meu, e com a pequena falta de tempo a documentação é curta. Tem os javadocs do projeto, se você usa o Eclipse quando você passa o mouse encima do método o Eclipse já completa a documentação.

Fazendo uma rápida explicação, todas as anotações possuem o campo message que se você deixa em branco ele pega as mensagens padrão. Ou vocẽ pode definir sua própria mensagem como você fez.

O campo formatted significa que o campo é formatado, caso contrário considero o campo como “somente numeros”. No caso um CPF válido será [CPF removido] e CNPJ 00.000.000/0000-00. Para CEP é considerado 00000-000 e telefone como 00.0000.0000.

O campo format é uma regex de como você quer que seja o formato válido para o campo. A classe RegexConstants [1] possui as regex usadas no projeto, e você pode se basear nelas para escrever seus próprios formatos.

Vou ver se consigo melhorar a documentação dele.

[1] http://github.com/garcia-jj/jsr303-br/blob/master/src/com/github/jsr303br/util/RegexConstants.java

Guevara

Opa!
Valeu Garcia! :smiley:
Segui então esse formato na inserção dos dados, mas não está passando pela validação:

@CPF(message="CPF inválido, digite novamente")
	private String cpf;
	@Telefone(message="Telefone incorreto, digite novamente")
	private String telefone;
	@Telefone(message="Celular incorreto, digite novamente")
	private String celular;

Deixei apenas as mensagens, e coloquei no formato que vc passou. Mesmo assim diz que o cpf e os telefones estão incorretos.

G

O padrão para formatted é FALSE, ou seja, se o CPF que você está passando é formatado você precisa colocar formatted=true.

Guevara

Pois é Garcia, eu fiz isso tb, passei o CPF como [CPF removido] e como [telefone removido], mesmo assim não valida.
O telefone parece que é validado com o formato [telefone removido] e não como 21.2547.4455.

G

Guevara, alguma coisa está errada aí. Note a classe de teste que tenho no projeto para validar se o CPF está correto:

http://github.com/garcia-jj/jsr303-br/blob/master/test/com/github/jsr303br/CPFTest.java

violations = validator.validate(new Cliente().setCpf1("[CPF removido]")); logger.debug(violations.toString()); Assert.assertTrue(violations.size() == 1);

public class Cliente { @CPF(formatted = true) public String cpf1; }

Guevara

Agora entendi, deu boa, a validação faz o cálculo mesmo para saber se é válido ou não:
http://www.profcardy.com/artigos/cpf.php
Para alterar o formato do telefone para “21-9999-9999” eu não tô conseguindo:

@Telefone(format="99-9999-9999", message="Telefone incorreto, digite novamente")

Tô seguindo o exemplo da sua classe: http://github.com/garcia-jj/jsr303-br/blob/268684e9d550b381055061346ba5cc87a978893e/test/com/github/jsr303br/TelefoneTest.java
É isso mesmo?
Abraço!!

Guevara

Lá no “format” do telefone eu coloco a expressão regular?

@Telefone(format=".-//d.-\\d\\d\\d\\d-\\d\\d\\d\\d",message="Telefone incorreto, digite novamente", formatted=true)

Tava precisando colocar os parênteses com o ddd ali:

16:35:44,970 DEBUG [OgnlParametersProvider] Applying proprietario.telefone with [([telefone removido]]
16:35:44,971 DEBUG [OgnlParametersProvider] Applying proprietario.celular with [([telefone removido]]

Abraço!

Guevara

Putz, consegui, segui este tutorial aqui:
http://www.vaniomeurer.com.br/tag/javautilregex/
Ficou assim:

@Telefone(format=".\\d\\d.\\d\\d\\d\\d-\\d\\d\\d\\d",message="Telefone incorreto, digite novamente", formatted=true)

Abraço!! \o/

G

Oi Guevara. Como eu tinha te dito no outro post você deve usar expressões regulares. Vou ver se essa semana melhoro a documentação dele.

Abraços

Guevara

Valeu Garcia!
Quando sair a documentação avise que eu vou baixar. =)
Esta validação ficou bem legal, tava pensando se seria possível fazer a validação para valores, anotar um atributo BigDecimal por exemplo. O problema seria o banco, pq o Hibernate cria a coluna como numeric(19,2) o valor fica assim 1504.00, ao invés de 1.504,00, pior ainda usando máscara no input. hehe
Abraço!!

G

Guevara, BigDecimal é sempre 1504.00 e não 1504,00. Quando você enxerga com virgulas isso é na verdade apenas uma representação do objeto formatado, mas não o objeto valor em sí. Se você quiser validar um valor como 1504,00 o seu campo precisa ser uma String ao invés de BigDecimal.

Guevara

Saquei, mas o problema é a máscara:

jQuery("#real").maskMoney({symbol:"R$",decimal:",",thousands:"."});

Vai mandar com ponto e vírgula, ai não dá pra salvar no banco. Eu tava pensando em alguma anotação que retirasse o ponto do milhar e a virgula do decimal, colocando o ponto no lugar, isso poderia ser feito por anotação tb, senão vou ter que criar um método usando replace para formatar o valor corretamente antes de ser persistido.
Tenho até outro tópico sobre isso.
http://www.guj.com.br/posts/list/217654.java
Abraço

G

Guevara, você pode usar uma regex no próprio Bean Validator anotando a propriedade com @Regex e passando uma expressão regular que faça o trabalho.

Abraços

Guevara

Oi Garcia!
Tô passando pra postar a solução:
Colocar no web.xml:

<context-param>  
     <param-name>br.com.caelum.vraptor.packages</param-name>      
     <param-value>br.com.caelum.vraptor.converter.l10n</param-value>  
 	</context-param>

Vi essa dica postada pelo Lucas em outro tópico. :smiley:
Agora sim, posso usar a máscara JQuery para valores, ao digitar o valor ele é convertido de 2.500,00 para 2500.00, no formato que o banco espera receber.
Abraço!!

G

Ahh, agora eu entendi o que você queria, hehe :slight_smile:

Abraços

Diego_Adriano

Guevara, como vc conseguiu resolver o problema do “javax.validation.ConstraintViolationException” a que se refere isso ?
Abraços

Criado 28 de agosto de 2010
Ultima resposta 28 de jun. de 2011
Respostas 34
Participantes 3