Validando CPF com Java através do Stella

(Last Updated On: 26 de outubro de 2017)

Trabalhamos em um ecommerce e fomos incubidos de cuidar de um bug que está ocorrendo no software da nossa empresa.

Para realizar a compra de algum produto é necessário fazer um cadastro no site. Nele pedimos algumas informações para o usuário, como por exemplo: Nome, email, endereço, telefone, CPF, entre outros.

O problema está ocorrendo exatamente no cadastro, alguns usuários estão colocando qualquer valor no campo de CPF e nosso software está permitindo isso. Nossa missão é conseguir capturar o CPF digitado e validá-lo.

Mas, e aí? Como se valida um CPF? Não faço a menor ideia! Para isso que existe o Google, certo? Vamos pesquisar:

  • CPF possui 11 dígitos
  • Multiplica-se os 9 primeiros dígitos pela sequência decrescente de números de 10 à 2 e soma os resultados obtidos

  • Multiplica-se o resultado acima por 10 e divide por 11, o resto da divisão é o penúltimo número do CPF (caso o resto seja 10, o resultado se torna 0). Logo se o número calculado for diferente do penúltimo número, o CPF é inválido.

  • Caso o primeiro dígito seja igual, multiplica-se os 10 primeiros dígitos pela sequência decrescente de números de 11

  • Multiplica-se a soma feita acima por 10

  • Verificamos se o resto da divisão da multiplicação acima por 11 é igual ao segundo dígito, se for, o CPF é válido.

Ah não, assim não dá, eu já me perdi na terceira regra. Validar CPF é algo muito complexo.

Parando para pensar, fazer esse tipo de validação deve ser uma tarefa comum para programadores, pois muitos sistemas necessitam dessa funcionalidade, logo, será que já não tem algo pronto?

Caelum Stella

Vendo esse tipo de funcionalidade sendo bastante requisitada por empresas e, consequentemente, pelos seus desenvolvedores, a Caelum decidiu criar o Stella, uma API que já traz todas as ferramentas necessárias para que possamos concluir nossa tarefa, ou seja, validar um cpf, de forma fácil e rápida.

O primeiro passo é instalar o Stella no nosso projeto. Para esse post, usaremos apenas o Stella Core, que já traz as funcionalidades principais dessa API.

Para instalar o Stella temos duas opções:

Podemos importar a dependência dele, caso o projeto use maven:

<dependency>
<groupId>br.com.caelum.stella</groupId>
<artifactId>caelum-stella-core</artifactId>
<version>2.1.2</version>
</dependency>

Ou apenas fazer o download do caelum-stella-core e importar o jar para o projeto.

Validando o CPF

Pronto, agora que acabamos de instalar só precisamos usar suas classes.

Bom, precisamos validar um CPF, certo? Então, primeiro vamos criar um método que nos devolve um boolean. Caso o CPF seja válido, nosso método irá retornar true, caso contrário, false. Vamos meter a mão na massa:

public boolean valida(String cpf){
}

Agora, precisamos instanciar a classe do Stella que cuida da validação do CPF. A classe que faz isso é a CPFValidator. Ficando assim:

public static boolean valida(String cpf){
   CPFValidator cpfValidator = new CPFValidator();
}

Boa, agora só precisamos usar o objeto criado e chamar seu método assertValid(), que recebe como parâmetro um CPF para ser validado:

public boolean valida(String cpf){
   CPFValidator cpfValidator = new CPFValidator();
   cpfValidator.assertValid(cpf);
}

Para conseguir o CPF que o método valida() requer, precisamos usar o getPessoaCpf() que nos devolve o CPF da pessoa que está se cadastrando. Com isso temos o seguinte código:

//main
String cpf = getPessoaCPF();
valida(cpf);

Boa, mas perceba que nosso método valida()está gerando um erro. No caso, ele está reclamando a falta de um retorno para esse método, pois declaramos que nosso método retorna um boolean e, por enquanto, não retornamos nada. E agora?

Poderíamos tentar retornar o método assertValid() mas olha o resultado:

Esse método retorna um void, ou seja, não retorna nada. Então como saber se nosso CPF é válido ou não? Se pegarmos a documentação do Stella a respeito desse método temos a seguinte implementação:

public void assertValid(String cpf) {
   List<ValidationMessage> errors = getInvalidValues(cpf);
   if (!errors.isEmpty()) {
      throw new InvalidStateException(errors);
   }
}

Vamos entender esse método. Ele recebe um CPF, e o manda para esse método getInvalidValues() que, por sua vez, vê se o CPF tem erros e no final adiciona todos os erros encontrados em uma lista e a retorna. Se a lista não estiver vazia, ou seja, conter algum erro, uma exceção é lançada.

Então caso tenha erro na lista, o método lança uma exceção. Logo, vamos envolver nosso código em um try/catch, se não tiver erro retornaremos true, caso tenha, false. Vamos lá:

public static boolean valida(String cpf) {
   CPFValidator cpfValidator = new CPFValidator();
   try{
      cpfValidator.assertValid(cpf);
      return true;
   }catch(Exception e){
      e.printStackTrace();
      return false;
   }
}

Para testar, ao invés de mandar o CPF retornado do método getCpfProduto vamos criar uma variável do tipo String e colocar nós mesmos valores para o CPF, assim:

String cpf = "357.672.271-87";
valida(cpf);

Esse CPF é válido, logo nossa implementação, em teoria, tem que nos retornar true. Além disso, vamos imprimir o boolean resultante do método para ver se nossa implementação está funcionando adequadamente:

String cpf = "357.672.271-87";
boolean valido = valida(cpf);
System.out.println(valido);

Agora vamos testar:

Muito bom, por enquanto tudo certo, mas e se o CPF fosse falso? Como seria? Vamos trocar alguns números e ver o que acontece:

Eita! Além de retornar false, ele lançou uma Exception. Se traduzirmos, basicamente ela diz: “Dígitos verificados inválidos”, mas o programa continuou funcionando perfeitamente.

O problema é que usar um try/catch nesse caso é algo inapropriado, devemos usar try/catch para tratar erros que não estamos esperando, para que, assim, possamos nos recuperar do erro obtido e, também, jogar regra de negócio dentro do bloco catch, não é nada legal.

O que seria o ideal? O ideal seria apenas retornarmos true caso não tenha erros e false caso tenha. Para isso vamos usar outro método do Stella.

Vocês se lembram do invalidMessagesFor? Que verifica se o CPF possui erros e devolve uma lista contendo esses erros, caso exista. Ele se adequa bem as nossas necessidades.

Se ele devolve uma lista vazia caso não tenha erros então vamos fazer uma condição que, caso a lista esteja vazia, retornará true,ou seja, cpf válido, caso não esteja, false, inválido.

Primeiro, vamos substituir todo o nosso try/catch por esse método e atribuí-lo a uma lista, assim:

public static boolean valida(String cpf) {
   CPFValidator cpfValidator = new CPFValidator();
   List<ValidationMessage> erros = cpfValidator.invalidMessagesFor(cpf);
}

Nos resta criar nossa condição que verifica se a lista possui erros:

//resto do código
List<ValidationMessage> erros = cpfValidator.invalidMessagesFor(cpf);
if(erros.size() > 0){
   return false;
}else{
   return true;
}

Pronto, para dar um toque final, além de retornar false, vamos imprimir os erros que aquele CPF possui, desse jeito:

if(erros.size() > 0){
   System.out.println(erros);//Sysout só para exemplificar, aqui você imprime seus erros, seja na web ou na sua aplicação
   return false;
}

Ainda usando um CPF inválido vamos rodar esse código para ver o que acontece:

Boa, não temos mais aquela exception lançada na nossa cara. Além disso, deixamos de utilizar o try/catch, muito bom! Para finalizar vamos só arrumar o código que estamos usando para migrar dos testes para os métodos reais que nosso programa utiliza:

String cpf = getPessoaCPF();
boolean valido = valida(cpf);
cadastra(valido);

Parabéns, conseguimos completar nossa missão! Validamos o CPF de forma fácil e rápida, agora quero ver os engraçadinhos tentarem comprar algum produto nosso passando um CPF falso.

Conclusão

Atualmente existem milhares de features prontas que resolvem muitos problemas encontrados por nós, programadores. Imaginem só se tivéssemos que escrever esse código de validação na mão? Pensa no trabalho que ia dar.

Antes de começar a programar coisas desse tipo, ou seja, funcionalidades comuns, pesquise na internet se já existe alguma que se encaixe com a sua necessidade, com certeza você vai ser muito mais produtivo.

E ai? Conhece outra API legal? Compartilhe aqui nos comentários, quem sabe você não acha alguma outra bacana ou ajuda alguém a encontrar uma que solucione algum problema de outro colega desenvolvedor.

Para saber mais

O Stella é muito maior do que apenas validação de CPF, com ele podemos gerar boletos customizados, calcular frete, formatar CPF e CNPJ e mais outras funcionalidades bem interessantes.

Na Alura temos o curso Java Brasil. Nele, outras funcionalidades muito úteis do Stella, como as citadas acima, são apresentadas. Para quem tem interesse em saber mais sobre essa linda API, vale a pena dar uma conferida.

E se você não programa em Java, existe, também, o Stella para C#. Na Alura, temos o curso C# Brasil. Neste curso você pode aprender diversas funcionalidades do Stella, usando a linguagem de programação C#.

FIQUE POR DENTRO

  • Michel de Almeida 

    Ótimo artigo. Existe alguma maneira do validador ignorar a pontuação do cpf e cnpj, validando apenas os números?

    • Henrique

      bom, isso seria uma string, certo?
      Então:

      int newCPF = cpf.replace( “.” , “”);

      Ou alguma expressão regular….

    • Mario Alvial

      Eai Michel, beleza? Então, o validator do Stella é espertão hahaha. Ele valida tanto CPF/CNPJ formatados (com “.” e “-“) quanto sem nada (só o número)

    • Michel de Almeida 

      Galera acabei resolvendo passando o parametro isFormatted como false

      CPFValidator(false)

Próximo ArtigoMelhore a experiência do usuário com Motion Design