🛡️ Validação de Dados com Bean Validation
Acesso Antecipado (Beta)Esta documentação refere-se a uma versão em acesso antecipado do SDK Sankhya. As funcionalidades e APIs estão sujeitas a modificações. Para obter acesso, envie um e-mail para [email protected] informando a
appkeydo seu projeto.
O Bean Validation é um mecanismo que permite definir e validar regras de negócio diretamente nos seus objetos de dados (DTOs e Entidades) usando anotações. O SDK Sankhya integra este padrão (especificação JSR 303/380), oferecendo validação automática e declarativa.
🤔 Por que usar Bean Validation?
- ✅ Validação Automática: Detecte dados inválidos antes que eles cheguem à sua lógica de negócio.
- ✅ Código Declarativo: As regras de validação ficam junto aos campos que elas validam, tornando o código mais legível.
- ✅ Mensagens de Erro Claras: Forneça feedback específico e customizável para o usuário final.
- ✅ Padrão de Mercado: Amplamente utilizado no ecossistema Java, o que facilita a adoção.
- ✅ Menos Código Boilerplate: Elimina a necessidade de
if/elsemanuais para validações.
🚀 Como Funciona?
O Bean Validation é ativado com a anotação @Valid. Quando um método de um @Service recebe um parâmetro anotado com @Valid, o SDK intercepta a chamada e executa todas as anotações de validação definidas no objeto.
Se qualquer validação falhar, o SDK lança uma exceção automaticamente, impedindo a execução do método e retornando uma resposta de erro clara.
Exemplo de Ativação:
@Service(name = "UsuarioServiceSP")
public class UsuarioService {
// ...
@Transactional
public void cadastrarUsuario(@Valid UsuarioDTO usuario) {
// O código dentro deste método só será executado
// se o objeto 'usuario' passar em todas as validações.
businessService.salvar(usuario);
}
}Anotações básicas de validação
1. Validações de Nulidade e Conteúdo
@NotNull
@NotNullGarante que o valor do campo não seja null.
@NotNull(message = "O ID do usuário é obrigatório.")
private Long id;@NotBlank
@NotBlankPara Strings. Garante que a string não seja null, vazia ("") ou contenha apenas espaços em branco.
@NotBlank(message = "O nome do usuário é obrigatório.")
private String nome;@NotEmpty
@NotEmptyPara coleções, mapas ou arrays. Garante que não sejam null e que tenham pelo menos um elemento.
@NotEmpty(message = "O pedido deve ter pelo menos um item.")
private List<ItemDTO> itens;2. Validações de Tamanho
@Size
@SizeVerifica se o tamanho de uma String, coleção, mapa ou array está dentro de um intervalo.
@Size(min = 3, max = 50, message = "O nome deve ter entre 3 e 50 caracteres.")
private String nome;
@Size(max = 5, message = "Um produto pode ter no máximo 5 tags.")
private List<String> tags;3. Validações Numéricas
@Min e @Max
@Min e @MaxGarante que um valor numérico seja maior ou igual (@Min) ou menor ou igual (@Max) a um limite.
@Min(value = 1, message = "A quantidade mínima é 1.")
private int quantidade;
@Max(value = 99, message = "O desconto máximo é 99%.")
private double desconto;@Positive e @PositiveOrZero
@Positive e @PositiveOrZeroGarante que um número seja estritamente positivo (> 0) ou positivo ou zero (>= 0).
@Positive(message = "O valor do produto deve ser positivo.")
private BigDecimal preco;@Negative e @NegativeOrZero
@Negative e @NegativeOrZeroGarante que um número seja estritamente negativo (< 0) ou negativo ou zero (<= 0).
4. Validações de Formato
@Email
@EmailVerifica se uma String tem um formato de e-mail válido.
@Email(message = "Formato de e-mail inválido.")
private String email;@Pattern
@PatternValida uma String contra uma expressão regular (RegEx).
@Pattern(regexp = "[A-Z]{2}[0-9]{4}", message = "A placa deve seguir o formato AA1234.")
private String placa;5. Validações de Data e Hora
@Future e @FutureOrPresent
@Future e @FutureOrPresentGarante que uma data esteja no futuro ou no futuro/presente.
@Future(message = "A data de entrega deve ser no futuro.")
private LocalDate dataEntrega;@Past e @PastOrPresent
@Past e @PastOrPresentGarante que uma data esteja no passado ou no passado/presente.
@PastOrPresent(message = "A data de nascimento não pode ser no futuro.")
private LocalDate dataNascimento;Validação aninhada (@Valid)
@Valid)Para validar objetos dentro de outros objetos (ex: uma lista de itens dentro de um pedido), use a anotação @Valid no campo do objeto aninhado.
// DTO do Pedido
public class PedidoDTO {
@NotNull
private Long idCliente;
@Valid // Ativa a validação para cada ItemDTO na lista
@NotEmpty
private List<ItemDTO> itens;
}
// DTO do Item
public class ItemDTO {
@NotNull
private Long idProduto;
@Positive(message = "A quantidade deve ser positiva.")
private int quantidade;
}Neste exemplo, ao validar um PedidoDTO, o SDK irá percorrer a lista de itens e aplicar as validações (@NotNull e @Positive) em cada ItemDTO.
✨ Boas Práticas
- Use em DTOs: A validação deve ocorrer na camada de entrada de dados. Portanto, aplique as anotações principalmente nos seus Data Transfer Objects (DTOs).
- Mensagens Claras: Sempre forneça uma
messageclara e útil para o usuário final. - Validações Customizadas: Para regras de negócio complexas, você pode criar suas próprias anotações de validação.
- Combine Anotações: É comum e recomendado usar múltiplas anotações em um mesmo campo (ex:
@NotNulle@Size).
2. Validações de Tamanho
@Size
@SizeDefine tamanho mínimo e/ou máximo para Strings, Collections, Arrays e Maps.
@Data
public class UsuarioDTO {
@Size(min = 2, max = 50, message = "Nome deve ter entre 2 e 50 caracteres")
private String nome;
@Size(min = 8, message = "Senha deve ter pelo menos 8 caracteres")
private String senha;
@Size(max = 5, message = "Máximo 5 endereços permitidos")
private List<EnderecoDTO> enderecos;
}@Length (Hibernate Validator)
@Length (Hibernate Validator)Similar ao @Size, mas específico para Strings.
@Data
public class ProdutoDTO {
@Length(min = 10, max = 500, message = "Descrição deve ter entre 10 e 500 caracteres")
private String descricao;
}3. Validações Numéricas
@Min e @Max
@Min e @MaxDefinem valores mínimos e máximos para números.
@Data
public class ProdutoDTO {
@Min(value = 0, message = "Preço não pode ser negativo")
private BigDecimal preco;
@Max(value = 100, message = "Desconto máximo é 100%")
private Integer percentualDesconto;
@Min(value = 1, message = "Quantidade mínima é 1")
@Max(value = 9999, message = "Quantidade máxima é 9999")
private Integer quantidade;
}@DecimalMin e @DecimalMax
@DecimalMin e @DecimalMaxValidação de valores decimais com maior precisão.
@Data
public class FinanceiroDTO {
@DecimalMin(value = "0.01", message = "Valor mínimo é 0.01")
private BigDecimal valor;
@DecimalMax(value = "999999.99", inclusive = false,
message = "Valor deve ser menor que 999999.99")
private BigDecimal limite;
}@Positive, @PositiveOrZero, @Negative, @NegativeOrZero
@Positive, @PositiveOrZero, @Negative, @NegativeOrZeroValidações para números positivos, negativos ou zero.
@Data
public class MovimentacaoDTO {
@Positive(message = "ID deve ser positivo")
private Long id;
@PositiveOrZero(message = "Saldo não pode ser negativo")
private BigDecimal saldo;
@NegativeOrZero(message = "Débito deve ser negativo ou zero")
private BigDecimal debito;
}@Digits
@DigitsValida o número de dígitos inteiros e fracionários.
@Data
public class MonetarioDTO {
@Digits(integer = 10, fraction = 2, message = "Formato: máximo 10 dígitos inteiros e 2 decimais")
private BigDecimal valor;
}4. Validações de Data e Tempo
@Past, @PastOrPresent
@Past, @PastOrPresentValidam datas no passado.
@Data
public class PessoaDTO {
@Past(message = "Data de nascimento deve estar no passado")
private LocalDate dataNascimento;
@PastOrPresent(message = "Data de cadastro deve ser hoje ou no passado")
private LocalDateTime dataCadastro;
}@Future, @FutureOrPresent
@Future, @FutureOrPresentValidam datas no futuro.
@Data
public class EventoDTO {
@Future(message = "Data do evento deve estar no futuro")
private LocalDateTime dataEvento;
@FutureOrPresent(message = "Data de entrega deve ser hoje ou no futuro")
private LocalDate dataEntrega;
}5. Validações de Formato
@Pattern
@PatternValida contra uma expressão regular.
@Data
public class ContatoDTO {
@Pattern(regexp = "^[A-Za-z0-9+_.-]+@(.+)$",
message = "Formato de email inválido")
private String email;
@Pattern(regexp = "\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}",
message = "CPF deve seguir o formato: 000.000.000-00")
private String cpf;
@Pattern(regexp = "\\(\\d{2}\\)\\s\\d{4,5}-\\d{4}",
message = "Telefone deve seguir o formato: (11) 99999-9999")
private String telefone;
}@Email
@EmailValidação específica para endereços de email.
@Data
public class UsuarioDTO {
@Email(message = "Email deve ter um formato válido")
@NotBlank(message = "Email é obrigatório")
private String email;
}6. Validações Booleanas
@AssertTrue e @AssertFalse
@AssertTrue e @AssertFalseValidam valores booleanos específicos.
@Data
public class TermosDTO {
@AssertTrue(message = "Deve aceitar os termos de uso")
private Boolean aceitaTermos;
@AssertFalse(message = "Não deve estar suspenso")
private Boolean suspenso;
}Tratamento de Erros de Validação
Quando uma validação falha, o sistema lança uma exceção contendo detalhes sobre todos os erros encontrados:
@Service(serviceName = "ProdutoServiceSP")
public class ProdutoController {
@Transactional
public void cadastrarProduto(@Valid ProdutoDTO produto) {
try {
produtoService.salvar(produto);
} catch (ConstraintViolationException e) {
// A exceção contém todos os erros de validação
e.getConstraintViolations().forEach(violation -> {
String campo = violation.getPropertyPath().toString();
String mensagem = violation.getMessage();
Object valorInvalido = violation.getInvalidValue();
System.err.printf("Erro no campo '%s': %s (valor: %s)%n",
campo, mensagem, valorInvalido);
});
// Re-lançar ou tratar conforme necessário
throw e;
}
}
}Exemplo Completo: Sistema de E-commerce
// DTO principal com validações completas
@Data
public class PedidoCompletoDTO {
@NotBlank(message = "Número do pedido é obrigatório")
@Pattern(regexp = "PED\\d{6}", message = "Número deve seguir o padrão: PED000000")
private String numeroPedido;
@Valid
@NotNull(message = "Dados do cliente são obrigatórios")
private ClienteDTO cliente;
@Valid
@NotEmpty(message = "Pedido deve conter pelo menos um item")
@Size(max = 50, message = "Máximo 50 itens por pedido")
private List<ItemPedidoDTO> itens;
@Valid
@NotNull(message = "Dados de entrega são obrigatórios")
private EnderecoEntregaDTO enderecoEntrega;
@FutureOrPresent(message = "Data de entrega deve ser hoje ou no futuro")
private LocalDate dataEntregaPrevista;
@DecimalMin(value = "0.00", message = "Valor total não pode ser negativo")
@Digits(integer = 8, fraction = 2, message = "Valor total deve ter no máximo 8 dígitos inteiros e 2 decimais")
private BigDecimal valorTotal;
@AssertTrue(message = "Deve aceitar os termos e condições")
private Boolean aceitaTermos;
}
@Data
public class ClienteDTO {
@NotBlank(message = "Nome é obrigatório")
@Size(min = 2, max = 100, message = "Nome deve ter entre 2 e 100 caracteres")
private String nome;
@Email(message = "Email deve ter formato válido")
@NotBlank(message = "Email é obrigatório")
private String email;
@ValidCPF(message = "CPF inválido")
@NotBlank(message = "CPF é obrigatório")
private String cpf;
@Pattern(regexp = "\\(\\d{2}\\)\\s\\d{4,5}-\\d{4}",
message = "Telefone deve seguir o formato: (11) 99999-9999")
private String telefone;
}
@Data
public class ItemPedidoDTO {
@NotBlank(message = "Código do produto é obrigatório")
@Pattern(regexp = "PROD\\d{4}", message = "Código deve seguir o padrão: PROD0000")
private String codigoProduto;
@NotBlank(message = "Nome do produto é obrigatório")
@Size(max = 200, message = "Nome do produto deve ter no máximo 200 caracteres")
private String nomeProduto;
@Positive(message = "Quantidade deve ser positiva")
@Max(value = 999, message = "Quantidade máxima por item é 999")
private Integer quantidade;
@DecimalMin(value = "0.01", message = "Preço unitário deve ser maior que zero")
@Digits(integer = 6, fraction = 2, message = "Preço deve ter no máximo 6 dígitos inteiros e 2 decimais")
private BigDecimal precoUnitario;
@DecimalMin(value = "0.00", message = "Subtotal não pode ser negativo")
private BigDecimal subtotal;
}
@Data
public class EnderecoEntregaDTO {
@NotBlank(message = "CEP é obrigatório")
@Pattern(regexp = "\\d{5}-?\\d{3}", message = "CEP deve ter o formato: 00000-000")
private String cep;
@NotBlank(message = "Logradouro é obrigatório")
@Size(max = 200, message = "Logradouro deve ter no máximo 200 caracteres")
private String logradouro;
@NotBlank(message = "Número é obrigatório")
@Size(max = 20, message = "Número deve ter no máximo 20 caracteres")
private String numero;
@Size(max = 100, message = "Complemento deve ter no máximo 100 caracteres")
private String complemento;
@NotBlank(message = "Bairro é obrigatório")
@Size(max = 100, message = "Bairro deve ter no máximo 100 caracteres")
private String bairro;
@NotBlank(message = "Cidade é obrigatória")
@Size(max = 100, message = "Cidade deve ter no máximo 100 caracteres")
private String cidade;
@NotBlank(message = "UF é obrigatória")
@Pattern(regexp = "[A-Z]{2}", message = "UF deve ter 2 letras maiúsculas")
private String uf;
}
// Controller com validação automática
@Service(serviceName = "EcommerceServiceSP")
public class EcommerceController {
private final PedidoService pedidoService;
@Inject
public EcommerceController(PedidoService pedidoService) {
this.pedidoService = pedidoService;
}
@Transactional
public String criarPedido(@Valid PedidoCompletoDTO pedido) {
// Todas as validações são executadas automaticamente
// antes de este método ser executado
return pedidoService.processar(pedido);
}
}Melhores Práticas
1. Combine Múltiplas Validações
@NotBlank(message = "Email é obrigatório")
@Email(message = "Email deve ter formato válido")
@Size(max = 100, message = "Email deve ter no máximo 100 caracteres")
private String email;2. Use Mensagens Descritivas
@Min(value = 18, message = "Idade mínima para cadastro é 18 anos")
private Integer idade;3. Valide Objetos Aninhados
@Valid
@NotNull(message = "Endereço é obrigatório")
private EnderecoDTO endereco;4. Organize por Grupos quando Necessário
@NotNull(groups = UpdateGroup.class)
@Null(groups = CreateGroup.class)
private Long id;O Bean Validation no SDK Sankhya oferece uma solução robusta e padronizada para validação de dados, garantindo a integridade das informações desde o ponto de entrada até a persistência, com feedback claro e automatizado para desenvolvedores e usuários finais.
Updated 11 days ago
