Starter Spring Boot para validação de documentos brasileiros, e-mail, senha, CEP, telefone e data de nascimento com Bean Validation (jakarta.validation).
Com br-validator, você valida CPF, CNPJ, e-mail, senha, CEP, telefone e data de nascimento de forma declarativa em DTOs, sem repetir regra de negócio em cada projeto.
- Principais funcionalidades
- Instalação
- Como usar
- Matriz de compatibilidade
- Tratamento de erro
- FAQ
- Tecnologias
- Roadmap
- Licença
- Annotation
@ValidCpfpara validação declarativa. - Annotation
@ValidCnpjpara validação declarativa. - Annotation
@ValidEmailpara validação declarativa. - Annotation
@ValidPasswordpara validação declarativa. - Annotation
@ValidCeppara validação declarativa. - Annotation
@ValidPhonepara validação declarativa. - Annotation
@ValidBirthDatepara validação declarativa. - Validação automática com Bean Validation.
- Serviços reutilizáveis para CPF, CNPJ, e-mail, senha, CEP, telefone e data de nascimento.
- Formatação de CPF, CNPJ e CEP.
- Geração de CPF e CNPJ válidos para testes.
- Auto-configuração Spring Boot para uso como dependência.
Adicione no pom.xml do seu projeto:
<dependencies>
<dependency>
<groupId>io.github.andrelamego</groupId>
<artifactId>br-validator</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>package com.example.demo.dto;
import io.github.andrelamego.brValidator.cpf.ValidCpf;
import io.github.andrelamego.brValidator.cnpj.ValidCnpj;
import io.github.andrelamego.brValidator.birthdate.ValidBirthDate;
import io.github.andrelamego.brValidator.cep.ValidCep;
import io.github.andrelamego.brValidator.email.ValidEmail;
import io.github.andrelamego.brValidator.password.ValidPassword;
import io.github.andrelamego.brValidator.phone.ValidPhone;
import java.time.LocalDate;
public class DocumentoRequest {
@ValidCpf(message = "CPF inválido", formatted = true, required = true)
private String cpf;
@ValidCnpj(message = "CNPJ inválido", formatted = true, required = false)
private String cnpj;
@ValidEmail(
message = "E-mail inválido",
required = true,
allowPlusAlias = true,
disposableAllowed = false,
allowedDomains = {"empresa.com"},
blockedDomains = {"bloqueado.com"}
)
private String email;
@ValidPassword(
message = "Senha inválida",
minLength = 8,
maxLength = 32,
requireUppercase = true,
requireLowercase = true,
requireNumber = true,
requireSpecialChar = true,
blockWhitespace = true
)
private String senha;
@ValidCep(formatted = true, required = true, rejectRepeatedDigits = true)
private String cep;
@ValidPhone(
formatted = true,
required = true,
allowLandline = false,
allowCountryCode = true,
rejectRepeatedDigits = true,
allowedAreaCodes = {"11", "21"},
blockedAreaCodes = {"31"}
)
private String telefone;
@ValidBirthDate(
required = true,
minAge = 18,
maxAge = 120,
allowFutureDate = false,
allowToday = true
)
private LocalDate dataNascimento;
}| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
CPF inválido. / CNPJ inválido. |
Mensagem de erro |
formatted |
boolean |
true |
Aceita documento com máscara |
required |
boolean |
true |
Define se o campo é obrigatório |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
Email inválido. |
Mensagem de erro |
required |
boolean |
true |
Define se o campo é obrigatório |
allowPlusAlias |
boolean |
true |
Aceita e-mails com alias + (ex: nome+tag@dominio.com) |
disposableAllowed |
boolean |
true |
Aceita domínios de e-mail descartável |
allowedDomains |
String[] |
{} |
Lista de domínios permitidos |
blockedDomains |
String[] |
{} |
Lista de domínios bloqueados |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
Senha inválida. |
Mensagem de erro |
required |
boolean |
true |
Define se o campo é obrigatório |
minLength |
int |
8 |
Tamanho mínimo da senha |
maxLength |
int |
64 |
Tamanho máximo da senha |
requireUppercase |
boolean |
true |
Exige pelo menos uma letra maiúscula |
requireLowercase |
boolean |
true |
Exige pelo menos uma letra minúscula |
requireNumber |
boolean |
true |
Exige pelo menos um número |
requireSpecialChar |
boolean |
true |
Exige pelo menos um caractere especial |
blockWhitespace |
boolean |
true |
Bloqueia espaços em branco na senha |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
CEP inválido. |
Mensagem de erro |
required |
boolean |
true |
Define se o campo é obrigatório |
formatted |
boolean |
true |
Aceita CEP com máscara |
rejectRepeatedDigits |
boolean |
true |
Rejeita CEP com todos os dígitos iguais |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
Telefone inválido. |
Mensagem de erro |
required |
boolean |
true |
Define se o campo é obrigatório |
formatted |
boolean |
true |
Aceita telefone com máscara |
allowLandline |
boolean |
false |
Permite telefone fixo |
allowCountryCode |
boolean |
true |
Permite prefixo de país (+55) |
rejectRepeatedDigits |
boolean |
true |
Rejeita sequências repetidas |
allowedAreaCodes |
String[] |
{} |
DDDs permitidos |
blockedAreaCodes |
String[] |
{} |
DDDs bloqueados |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
message |
String |
Data de Nascimento inválida. |
Mensagem de erro |
required |
boolean |
true |
Define se o campo é obrigatório |
minAge |
int |
0 |
Idade mínima permitida |
maxAge |
int |
120 |
Idade máxima permitida |
allowFutureDate |
boolean |
false |
Permite datas futuras |
allowToday |
boolean |
true |
Permite data igual a hoje |
groups |
Class<?>[] |
- | Bean Validation |
payload |
Payload[] |
- | Bean Validation |
import io.github.andrelamego.brValidator.birthdate.BirthDateValidationService;
import io.github.andrelamego.brValidator.cep.CepValidationService;
import io.github.andrelamego.brValidator.cpf.CpfValidationService;
import io.github.andrelamego.brValidator.cnpj.CnpjValidationService;
import io.github.andrelamego.brValidator.email.EmailValidationService;
import io.github.andrelamego.brValidator.password.PasswordValidationService;
import io.github.andrelamego.brValidator.phone.PhoneValidationService;
import java.time.LocalDate;
// Exemplo considerando os services já injetados no seu bean.
// 1) Validação padrão
boolean cpfValido = cpfValidationService.isValid("529.982.247-25");
boolean cnpjValido = cnpjValidationService.isValid("04.252.011/0001-10");
boolean emailValido = emailValidationService.isValid("usuario@empresa.com");
boolean senhaValida = passwordValidationService.isValid("Senha@123");
boolean cepValido = cepValidationService.isValid("01310-100", true, true);
// 2) Validação com regras específicas
boolean dataNascimentoValida = birthDateValidationService.isValid(
LocalDate.of(2000, 1, 1),
18, // minAge
120, // maxAge
false, // allowFutureDate
true // allowToday
);
String[] dddsPermitidos = {"11"};
String[] dddsBloqueados = {"31"};
boolean telefoneValido = phoneValidationService.isValid(
"+55 (11) 98765-4321",
true, // formatted
false, // allowLandline
true, // allowCountryCode
true, // rejectRepeatedDigits
dddsPermitidos,
dddsBloqueados
);
boolean emailRestritoValido = emailValidationService.isValid(
"usuario+tag@empresa.com",
true,
false,
new String[]{"empresa.com"},
new String[]{"bloqueado.com"}
);
boolean senhaRestritaValida = passwordValidationService.isValid(
"Senha@123",
8, // minLength
32, // maxLength
true, // requireUppercase
true, // requireLowercase
true, // requireNumber
true, // requireSpecialChar
true // blockWhitespace
);
// 3) Formatação e geração
String cepFormatado = cepValidationService.formatar("01310100");
String cpfFormatado = cpfValidationService.formatar("52998224725");
String cnpjFormatado = cnpjValidationService.formatar("04252011000110");
String cpfGerado = cpfValidationService.gerarCpfValido();
String cnpjGerado = cnpjValidationService.gerarCnpjValido();package com.example.demo.controller;
import com.example.demo.dto.DocumentoRequest;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/documentos")
public class DocumentoController {
@PostMapping
public String criar(@RequestBody @Valid DocumentoRequest request) {
return "Documento válido";
}
}{
"cpf": "529.982.247-25",
"cnpj": "04.252.011/0001-10",
"email": "usuario@empresa.com",
"senha": "Senha@123",
"cep": "01310-100",
"telefone": "+55 (11) 98765-4321",
"dataNascimento": "2000-01-01"
}| Componente | Versão |
|---|---|
| Java | 21 |
| Spring Boot | 4.0.x (testado com 4.0.5) |
| Maven | 3.9+ |
| Jakarta Validation | 3.x |
| Hibernate Validator | 9.x |
As annotations (@ValidCpf, @ValidCnpj, @ValidEmail, @ValidPassword, @ValidCep, @ValidPhone e @ValidBirthDate) retornam erro de validação via Bean Validation.
Já os métodos formatar(...) de CPF/CNPJ/CEP lançam exceção quando o documento é inválido.
package com.example.demo.api;
import io.github.andrelamego.brValidator.cnpj.InvalidCnpjException;
import io.github.andrelamego.brValidator.cpf.InvalidCpfException;
import io.github.andrelamego.brValidator.cep.InvalidCepException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Map;
@RestControllerAdvice
public class ApiExceptionHandler {
@ExceptionHandler({InvalidCpfException.class, InvalidCnpjException.class, InvalidCepException.class})
public ResponseEntity<Map<String, String>> handleDocumentoInvalido(RuntimeException ex) {
return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleBeanValidation(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream()
.findFirst()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.orElse("Dados inválidos");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("error", message));
}
}Sim. Por padrão, formatted = true.
Sim. Use formatted = false na annotation ou isValid(documento, false) no service.
Sim. Use required = false nas annotations.
Sim, por padrão (allowPlusAlias = true).
Sim. Use disposableAllowed = false.
Sim. Use allowedDomains e blockedDomains.
Sim. Por padrão, formatted = true em @ValidCep.
Depende da configuração. Em @ValidPhone, o padrão é allowLandline = false.
Sim. Use allowedAreaCodes e blockedAreaCodes em @ValidPhone.
Não por padrão. Use allowFutureDate = true em @ValidBirthDate se precisar permitir.
Não. O service retorna false.
Não. O service retorna false.
Não. O service retorna false.
Mínimo de 8 caracteres, máximo de 64, com maiúscula, minúscula, número, caractere especial e sem espaços.
Em formatar(...), quando CPF/CNPJ/CEP é inválido.
- Java 21
- Spring Boot
- Maven
- Jakarta Validation
- Hibernate Validator
Melhorias previstas:
- Evoluir regras avançadas de validação para CEP e telefone
- Adicionar internacionalização das mensagens de validação (i18n)
- Expandir documentação com exemplos por domínio
- Testes automatizados mais robustos
- Suporte a múltiplos formatos de documento
Este projeto está sob a licença MIT.
Consulte o arquivo LICENSE.