Início > programação, programação JSF > Implementando converter e validator de CPF

Implementando converter e validator de CPF

Recentemente me deparei no trabalho com alguns sistemas que exigiam a validação/formatação de CPF e de CNPJ. Achei que poderia solucionar o problema com javascript, mas considerei melhor criar validator e converter para cada um dos casos.

Nessa primeira etapa, vou mostrar a conversão e validação de CPF. Ressalto que a lógica de validação/conversão vai estar completamente inserida dentro das classes que implementam javax.faces.convert.Converter e javax.faces.validator.Validator. Aqui no meu trabalho colocamos essa lógica em classes Java separadas. Geramos um jar com essas classes e então colocamos esse jar no classpath da aplicação, evitando replicação de código.

Para começar, vamos estudar alguns conceitos:

O que é um converter?

Um converter pode ser uma classe java que implemente javax.faces.converter.Converter ou pode-se utilizar tags do próprio jsf. É usado para formatar um objeto de uma forma que ele fique mais adequado para visualização. Por exemplo: é melhor visualizar uma data no formato 05-30-2009 ou no formato brasileiro: 30/05/3009?

O que é um validator?

Da mesma forma do converter, um validator pode ser uma classe java que implementa javax.faces.validator.Validator ou pode-se utilizar tags do próprio jsf. É utilizado para validar valores fornecidos pelo usuário nos formulários, assegurando que o campo foi preenchido com o valor esperado.  Um exemplo prático é validar o CEP que o usuário forneceu – se ele colocou somente números , por exemplo.

Conversão e Validação no ciclo do JSF

No ciclo do JSF, caso o input tenha o immediate setado como false, a validação e a conversão acontecem em fases diferentes, conforme a imagem abaixo:

Ciclo JSF

Ciclo JSF

Já se o atributo immediate estiver como true, a validação e a conversão acontecem na fase Apply Request Values (Aplicar Valores de Requisição), conforme a figura que se segue:

Ciclo JSF com Immediate

Ciclo JSF com Immediate


Vamos aos exemplos práticos:

  • A Classe Java de Conversão de CPF:

package br.com.conversor;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

/**
* Conversor de CPF.
*
* @author Pablo Nóbrega
*/
public class CpfConverter implements Converter {
     public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
         /*
          * Irá converter CPF formatado para um sem pontos e traço.
          * Ex.: 355.245.198-87 torna-se 35524519887.
          */
          String cpf = value;
          if (value!= null && !value.equals(""))
               cpf = value.replaceAll("\\.", "").replaceAll("\\-", "");

          return cpf;
     }

     public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
         /*
          * Irá converter CPF não formatado para um com pontos e traço.
          * Ex.: 35524519887 torna-se 355.245.198-87.
          */
          String cpf= value;
          if (cpf != null && cpf.length() == 11)
               cpf = cpf.substring(0, 3) + "." + cpf.substring(3, 6) + "." + cpf.substring(6, 9) + "-" + cpf.substring(9, 11);

          return cpf;
     }
}

  • Declarando o converter de CPF no faces-config:

<converter>
     <converter-id>converter.CpfConverter</converter-id>
     <converter-class>br.com.converter.CpfConverter</converter-class>
</converter>

  • Para fazer a chamada do converter de CPF em um campo texto:
<h:outputText value="CPF: " />
<h:outputText value="#{cliente.cpf}">
     <f:converter converterId="converter.CpfConverter" />
</h:outputText>

Com esse código, o trecho da página aparecerá da seguinte forma:

CPF: 254.452.153-62

Vale ressaltar que estamos levando em conta que o valor original do CPF está com 11 dígitos e sem nenhum caractere delimitando grupos de números.


  • A Classe Java de Validação de CPF:

package br.com.validator;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import java.util.ResourceBundle;

/**
* Validação de CPF.
*
* @author Pablo Nóbrega
*/
public class CpfValidator implements Validator {
     @Override
     public void validate(FacesContext arg0, UIComponent arg1, Object valorTela) throws ValidatorException {
          if (!validaCPF(String.valueOf(valorTela))) {
               FacesMessage message = new FacesMessage();
               message.setSeverity(FacesMessage.SEVERITY_ERROR);
               message.setSummary(ResourceBundle.getBundle(FacesContext.getCurrentInstance().getApplication().getMessageBundle()).getString("erro.validacao.cpf"));
               throw new ValidatorException(message);
          }
     }

     /**
     * Valida CPF do usuário. Não aceita CPF's padrões como
     * 11111111111 ou 22222222222
     *
     * @param cpf String valor com 11 dígitos
     */
     private static boolean validaCPF(String cpf) {
          if (cpf == null || cpf.length() != 11 || isCPFPadrao(cpf))
               return false;

          try {
               Long.parseLong(cpf);
          } catch (NumberFormatException e) { // CPF não possui somente números
	       return false;
          }

	  return calcDigVerif(cpf.substring(0, 9)).equals(cpf.substring(9, 11));
     }

     /**
     *
     * @param cpf String valor a ser testado
     * @return boolean indicando se o usuário entrou com um CPF padrão
     */
     private static boolean isCPFPadrao(String cpf) {
          if (cpf.equals("11111111111") || cpf.equals("22222222222")
		|| cpf.equals("33333333333")
		|| cpf.equals("44444444444")
		|| cpf.equals("55555555555")
		|| cpf.equals("66666666666")
		|| cpf.equals("77777777777")
		|| cpf.equals("88888888888")
		|| cpf.equals("99999999999")) {

               return true;
          }

	  return false;
     }

     private static String calcDigVerif(String num) {
          Integer primDig, segDig;
	  int soma = 0, peso = 10;
	  for (int i = 0; i < num.length(); i++)
	       soma += Integer.parseInt(num.substring(i, i + 1)) * peso--;

	  if (soma % 11 == 0 | soma % 11 == 1)
	       primDig = new Integer(0);
          else
               primDig = new Integer(11 - (soma % 11));

	  soma = 0;
          peso = 11;
          for (int i = 0; i < num.length(); i++)
               soma += Integer.parseInt(num.substring(i, i + 1)) * peso--;

          soma += primDig.intValue() * 2;
          if (soma % 11 == 0 | soma % 11 == 1)
               segDig = new Integer(0);
          else
               segDig = new Integer(11 - (soma % 11));

          return primDig.toString() + segDig.toString();
     }
}

  • Declarando o validator de CPF no faces-config:

<validator>
     <validator-id>converter.CpfValidator</validator-id>
     <validator-class>br.com.validator.CpfValidator</validator-class>
</validator>

  • Para fazer a chamada do validator de CPF em um campo do formulário:

<h:inputText value="#{cliente.cpf}" required="true" maxlength="11">
     <f:validator validatorId="validator.CpfValidator" />
</h:inputText>

  • Por fim, precisamos colocar no bundle a mensagem de erro de validação de CPF:

erro.validacao.cpf=CPF inválido.

  • E uma chamada ao h:messages na página em que o validator está inserido, conforme exemplo abaixo, para que o erro seja exibido:

<h:messages />

A imagem abaixo mostra o erro exibido ao usuário quando um CPF inválido é fornecido pelo usuário em um dos sistemas da nossa empresa.

Mensagem CPF inválido

Mensagem CPF inválido

Referências:

  • GEARY, David; Horstmann, Cay. Core Java Server Faces. 2. ed.: Sun MicroSystems Press, 2007. 645 p.
  • HIGHTOWER, Richard; TABOR, Paul; JSF for nonbelievers: JSF conversion and validation. Disponível em: <http://www.ibm.com/developerworks/java/library/j-jsf3/&gt; Acesso em: 20 de julho de 2009.
Anúncios
  1. William
    10/09/2009 às 19:38

    Ola Pablo,

    Estou pesquisando muito sobre validaçao de Cpf em java,pois preciso implementar um campo assim na minha aplicaçao java desktop,sera que esse seu exemplo pode ser implementado na minha aplicaçao desktop?

    obrigado

  2. 14/09/2009 às 08:08

    Very nice site!

  3. 21/04/2010 às 17:21

    legal Pablo, outra forma tb que temos usando JSF é usar REGEX nos nossos validadores eh uma forma fácil, rápida e eficiente. o site a seguir tem alguns regex ja prontos para validacao de e-mail, telefone etc. Na verdade é um Testador Online regex. veja: http://tools.lymas.com.br/regexp_br.php#
    flw! 😀

  4. Raphael
    17/06/2010 às 13:09

    Olá Pablo,

    Você poderia me mandar essa classe FormatoCPFException ?

    Obrigado

    • 17/06/2010 às 15:00

      Olá Raphael. Ela na verdade é uma classe bem simples que extende Exception. Vou mandar o código para seu e-mail.

  5. Haylson Martins
    10/10/2010 às 16:24

    Olá Pablo, gostei muito do seu exemplo… bem esclarecedor… só não consegui colocar pra rodar porque nao tem essa classe FormatoCPFException, que não sei fazer… pode me mandar tbem pra eu dar uma olhada.

    agradeço.

    • 10/10/2010 às 22:06

      Olá Haylson. Na verdade essa é uma classe simples que extende Exception. O código seria o seguinte:

      public class FormatoCPFException extends Exception {

      private static final long serialVersionUID = -3598703361134335043L;

      public FormatoCPFException() {
      super();
      }

      public FormatoCPFException(String msg){
      super(msg);
      }
      }

  6. Mauricio Rosa
    20/09/2012 às 11:56

    Olá Pablo,

    Primeiramente gostaria de parabeniza-lo pelo conteúdo disponibilizado.
    Mas não esotu manjando como faz esta parte do “bundle” e tbm esta dando o seguinte erro quando tento executar o projeto:
    “GRAVE: JSF1005: Não pode criar instância para o validador de tipo validator.CpfValidator”
    Não sei o que pode ser isso.
    Tem que fazer mais alguma configuração no faces-config.xml ou no web.xml?
    Você poderia me mandar o projeto deste tutorial?

    Att,

    • 20/09/2012 às 13:58

      Maurício,

      Você está usando JSF 1.2 ou 2? Os exemplos são para JSF 1.2. Não há mais nenhuma configuração no faces-config.xml nem no web.xml.

      • Mauricio Rosa
        20/09/2012 às 14:10

        Então estou usando o JSF 2.1, será que este o problema então?

      • 20/09/2012 às 15:07

        Fala Maurício.

        Cara o problema é esse. No JSF 2, você nem precisa declarar os converters e validators no faces-config.xml.

        Faz assim: sua classe vai implementar javax.faces.convert.Converter e você deve colocar a annotation na classe @FacesConverter com o atributo value setado para você determinar como vai chamá-la na tela. Exemplo: @FacesConverter(value = “converter.CPFConverter”)

        No teu e-mail mando um exemplo.

  7. Glaucia
    26/09/2012 às 09:42

    Estou criando uma calculadora em Java Web só que preciso validar o campo de numero para que o usuário digite apenas número como faço isso?

    • 26/09/2012 às 09:56

      Gláucia,

      Você está usando o que? JSF 2? JSF 1.2? Servlets? Servlets + JSP? Se for JSF, qual o framework de RIA você está usando? Primefaces, Icefaces, Richfaces?

      Aguardo retorno.

  8. Eduardo Januário
    14/11/2012 às 21:14

    Olá Pablo,
    Sou iniciante em java e este post já me ajudou muito, porém estou com algumas dificuldades, vamos ver se você poderá me ajudar:

    01) Não descobri onde a classe FormatoCPFException é utilizada, eu até criei, utilizando o eclipse => new => class => Name: FormatoCPFException => SuperClass: java.lang.Exception => Marquei : Constructors form superclass e Inherited abstract methods, mas em nenhum momento tive que fazer o import desta classe.

    02) Mesmo usando o J.S.F.2.0 incluí os conversores e validadores no faces-config e parece que eles foram interpretados corretamente.

    03) Me enrolei um pouco com bundle , fiz o seguinte criei um novo package e inclui um arquivo que chamei de mensagens.properties e inclui a linha : erro.validacao.cpf=CPF inválido, depois alterei o faces-config incluindo as seguintes linha:

    com.recursos
    msg

    04) Em meu formulário :

    Executando no Eclipse, através do debbug, verifiquei que a conversão é feita perfeitamente, mas na validação, quando digito um cpf válido, ocorre tudo perfeitamente, porém quando digito um cpf inválido, ocorre “java.lang.NullPointerException” na linha “message.setSummary(ResourceBundle.getBundle(FacesContext.getCurrentInstance().getApplication().getMessageBundle()).getString(“erro.validacao.cpf”));” da classe CPF Validator.

    Utilizo o JSF 2.0 com PrimeFaces, acho que o erro ocorre no momento que a exceção é lançada, porém não consigo descobrir. Será que você pode me ajudar?
    Muito Obrigado.

    Eduardo

    • 15/11/2012 às 11:07

      Eduardo,

      Na verdade fiz uma atualização no post e a classe FormatoCPFException passou a não ser mais usada. Pode descartá-la. Vou consertar o tutorial.

      No JSF 2, você não precisa declarar os converters e validators no faces-config.xml. Basta colocar as anotações nos dois. No caso, faça da seguinte forma e retire as declarações do faces-config.xml:

      @FacesConverter(value = “converter.CpfConverter”)
      public class CpfConverter implements Converter

      @FacesConverter(value = “validator.CpfValidator”)
      public class CpfValidator implements Validator

      Sempre uso o resource bundle fora de qualquer pacote (na raiz mesmo) para facilitar a declaração no faces-config.xml. O nome do arquivo é messages_pt_BR.properties e a declaração fica assim:


      <application>
      <resource-bundle>
      <base-name>messages</base-name>
      <var>msgs</var>
      </resource-bundle>
      <message-bundle>messages_pt_BR</message-bundle>
      <locale-config>
      <default-locale>pt_BR</default-locale>
      </locale-config>
      </application>

      O erro de NullPointerException provavelmente é porque a classe não encontrou o resource bundle. Caso não seja isso, segue um código que vai funcionar no JSF 2:


      FacesMessage message = new FacesMessage();
      message.setSeverity(FacesMessage.SEVERITY_ERROR);
      message.setSummary(MessageFormat.format(FacesContext.getCurrentInstance().getApplication().getResourceBundle(FacesContext.getCurrentInstance(), "msgs").getString("erro.validacao.cpf"));
      throw new ValidatorException(message);

      Abraço.

      • Eduardo Januário
        15/11/2012 às 14:07

        Caro Pablo,
        Segui suas orientações e funcionou perfeitamente. Estou impressionado com a sua disposição em ajudar-nos, pobres iniciantes.
        Mais uma vez, muito Obrigado.
        Um abraço.
        Eduardo

  9. heitor Lavoyer de Lima
    20/11/2012 às 13:53

    como eu adiciono esse bundle?

  10. heitor Lavoyer de Lima
    20/11/2012 às 13:58

    Boa tarde,

    Muito bom o seu exemplo, só que eu estou com um problema, onde eu adiciono este bundle? ele e na classe java onde esta a validação? e na classe onde os dados são armazenados? estou com esta duvida… o meu esta dando o erro java.lang.NullPointerException” na linha “message.setSummary(ResourceBundle.getBundle(FacesContext.getCurrentInstance…
    Será que você poderiia me ajudar?

    Desde ja agradeço

    • 21/11/2012 às 09:20

      Heitor,

      Desculpa a demora para responder. Adicionar um resource bundle em uma aplicação JSF, é igual em qualquer aplicação Java WEB. A minha abordagem é a seguinte: crio um arquivo texto chamado messages_pt_BR.properties dentro da pasta raiz dos pacotes de classes java. No faces-config.xml faço o seguinte:


      <application>
      <resource-bundle>
      <base-name>messages</base-name>
      <var>msgs</var>
      </resource-bundle>
      <message-bundle>messages_pt_BR</message-bundle>
      <locale-config>
      <default-locale>pt_BR</default-locale>
      </locale-config>
      </application>

      Nesse arquivo você vai colocar os pares chave/valor que deseja para deixar a aplicação pronta para internacionalização, como o exemplificado no post:


      erro.validacao.cpf=CPF inválido.

      Pronto! Basta isso.

  11. Rafael
    26/07/2013 às 15:20

    Estou fazendo no JSF 2 e recebo a mensagem :”Type Mismatch Can not convert from Object to String ”

    no seguinte trecho:

    public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
    /*
    * Irá converter CPF não formatado para um com pontos e traço.
    * Ex.: 35524519887 torna-se 355.245.198-87.
    */

    String cpf= value; <—-AQUI RECEBO ESTA MENSAGEM

    if (cpf != null && cpf.length() == 11)
    cpf = cpf.substring(0, 3) + "." + cpf.substring(3, 6) + "." + cpf.substring(6, 9) + "-" + cpf.substring(9, 11);

    return cpf;

    • 26/07/2013 às 18:09

      Rafael,

      Experimente colocar um cast.

      String cpf = (String) value;

      Abraço,

      Pablo.

  12. 05/08/2014 às 14:34

    Caso esteja gerando “NullPointerException”

    Troque isso:

    FacesMessage message = new FacesMessage();
    message.setSeverity(FacesMessage.SEVERITY_ERROR); message.setSummary(ResourceBundle.getBundle(FacesContext.getCurrentInstance().
    getApplication().getMessageBundle()).getString(“erro.validacao.cpf”));
    throw new ValidatorException(message);

    Por :

    FacesMessage message = new FacesMessage();
    message.setSeverity(FacesMessage.SEVERITY_ERROR);
    message.setSummary(“CPF Inválido.”);
    throw new ValidatorException(message);

  1. 03/01/2011 às 23:29

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: