DEV Community

Uiratan Cavalcante
Uiratan Cavalcante

Posted on

Validando CPF e CNPJ com uma Annotation Customizada em Java

No mundo do desenvolvimento de software, validações são um aspecto essencial para garantir que os dados inseridos pelos usuários estejam corretos. Em Java, você pode criar validações personalizadas para diferentes cenários. Neste post, vamos aprender como criar uma annotation customizada para validar documentos como CPF e CNPJ utilizando o pacote javax.validation.

O que vamos fazer?

Vamos criar uma annotation chamada @CPFCNPJ que pode ser aplicada em campos que recebem um CPF ou CNPJ. A annotation vai utilizar um validador customizado, chamado DocumentoValidator, que será responsável por verificar se o valor inserido é válido de acordo com as regras do CPF ou CNPJ.

Passo 1: Criando a Annotation @CPFCNPJ

Primeiramente, criamos a annotation que será usada para marcar os campos que precisam ser validados. Aqui está o código da annotation:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = DocumentoValidator.class) // Indica qual será o validador
@Target({ ElementType.FIELD }) // Aplica-se a campos
@Retention(RetentionPolicy.RUNTIME) // Disponível em tempo de execução
public @interface CPFCNPJ {
    String message() default "Documento inválido"; // Mensagem padrão de erro
    Class<?>[] groups() default {}; // Para agrupar validações
    Class<? extends Payload>[] payload() default {}; // Para adicionar dados adicionais ao validador
}
Enter fullscreen mode Exit fullscreen mode

Neste código:

  • A annotation @Constraint associa a annotation @CPFCNPJ ao validador DocumentoValidator.
  • A annotation pode ser aplicada a campos com @Target({ ElementType.FIELD }).
  • A mensagem de erro padrão é "Documento inválido", mas pode ser personalizada.
  • groups e payload são utilizados em validações mais avançadas, mas não são necessários para este exemplo básico.

Passo 2: Criando o Validador DocumentoValidator

Agora, vamos criar a classe DocumentoValidator, que será responsável por validar os documentos CPF e CNPJ. Ela implementa a interface ConstraintValidator, que recebe a annotation e o tipo de dado a ser validado (no nosso caso, uma string que representa o CPF ou CNPJ).

Aqui está o código do DocumentoValidator:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class DocumentoValidator implements ConstraintValidator<CPFCNPJ, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || value.isEmpty()) {
            return false; // Se o campo for nulo ou vazio, é considerado inválido
        }

        return validarDocumento(value); // Chama o método que valida CPF ou CNPJ
    }

    private static boolean validarCPF(String cpf) {
        if (cpf == null || cpf.length() != 11 || !cpf.matches("[0-9]{11}")) {
            return false;
        }

        if (cpf.matches("(\\d)\\1{10}")) {
            return false; // Não permite CPFs com números repetidos
        }

        int soma = 0;
        int peso = 10;
        for (int i = 0; i < 9; i++) {
            soma += Character.getNumericValue(cpf.charAt(i)) * peso--;
        }

        int digito1 = 11 - (soma % 11);
        if (digito1 == 10 || digito1 == 11) digito1 = 0;

        soma = 0;
        peso = 11;
        for (int i = 0; i < 10; i++) {
            soma += Character.getNumericValue(cpf.charAt(i)) * peso--;
        }

        int digito2 = 11 - (soma % 11);
        if (digito2 == 10 || digito2 == 11) digito2 = 0;

        return digito1 == Character.getNumericValue(cpf.charAt(9)) && digito2 == Character.getNumericValue(cpf.charAt(10));
    }

    private static boolean validarCNPJ(String cnpj) {
        if (cnpj == null || cnpj.length() != 14 || !cnpj.matches("[0-9]{14}")) {
            return false;
        }

        if (cnpj.matches("(\\d)\\1{13}")) {
            return false; // Não permite CNPJs com números repetidos
        }

        int soma = 0;
        int[] peso1 = {5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2};
        for (int i = 0; i < 12; i++) {
            soma += Character.getNumericValue(cnpj.charAt(i)) * peso1[i];
        }

        int digito1 = 11 - (soma % 11);
        if (digito1 == 10 || digito1 == 11) digito1 = 0;

        soma = 0;
        int[] peso2 = {6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2};
        for (int i = 0; i < 13; i++) {
            soma += Character.getNumericValue(cnpj.charAt(i)) * peso2[i];
        }

        int digito2 = 11 - (soma % 11);
        if (digito2 == 10 || digito2 == 11) digito2 = 0;

        return digito1 == Character.getNumericValue(cnpj.charAt(12)) && digito2 == Character.getNumericValue(cnpj.charAt(13));
    }

    private static boolean validarDocumento(String documento) {
        if (documento == null) {
            return false;
        }

        documento = documento.replaceAll("[^0-9]", "");  // Remove caracteres não numéricos

        if (documento.length() == 11) {
            return validarCPF(documento);
        } else if (documento.length() == 14) {
            return validarCNPJ(documento);
        }

        return false;  // Se o comprimento não for nem 11 nem 14, retorna inválido
    }
}
Enter fullscreen mode Exit fullscreen mode

Passo 3: Utilizando a Annotation

Agora que já criamos a annotation e o validador, podemos aplicá-los em um modelo de dados. Por exemplo, vamos validar um CPF ou CNPJ em um campo de um DTO (Data Transfer Object).

import javax.validation.constraints.NotEmpty;

public class UsuarioDTO {

    @CPFCNPJ(message = "CPF ou CNPJ inválido") // Aplica a validação customizada
    @NotEmpty(message = "Documento não pode ser vazio")
    private String documento;

    // Getters e Setters

    public String getDocumento() {
        return documento;
    }

    public void setDocumento(String documento) {
        this.documento = documento;
    }
}
Enter fullscreen mode Exit fullscreen mode

Passo 4: Realizando a Validação

Para realizar a validação, você pode usar o Validator do Bean Validation. Aqui está um exemplo simples de como validar a classe UsuarioDTO:

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.ConstraintViolation;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        UsuarioDTO usuario = new UsuarioDTO();
        usuario.setDocumento("123.456.789-09");  // Insira o CPF ou CNPJ a ser validado

        // Cria o validador
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        // Valida o objeto
        Set<ConstraintViolation<UsuarioDTO>> violations = validator.validate(usuario);

        // Verifica se há erros
        for (ConstraintViolation<UsuarioDTO> violation : violations) {
            System.out.println(violation.getMessage());  // Exibe a mensagem de erro
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusão

Neste post, mostramos como criar uma annotation customizada para validar CPF e CNPJ em Java. Utilizamos a especificação Bean Validation (JSR 303) para criar a annotation @CPFCNPJ, um validador DocumentoValidator e mostramos como aplicar e utilizar a validação em um campo de um modelo de dados.

Com isso, você pode facilmente validar CPFs e CNPJs em seus projetos Java, mantendo o código limpo e reutilizável.

Top comments (0)