DEV Community

Andre Barreto
Andre Barreto

Posted on • Updated on

Introdução ao Bean Validation: Deixe o Java Trabalhar!

Introdução

A validação de dados é uma parte importante e corriqueira de qualquer sistema, seja ela a partir de dados informados por um usuário humano, um androide, uma I.A...

Porém, também é uma das tarefas mais maçantes que temos que realizar enquanto programadores. Normalmente, no back-end, ela é feita de forma manual na camada de controle ou de serviços, utilizando-se no pior caso If's alinhados e no menos pior métodos e classes específicas.


Validação manual
Típica validação manual

Ok! Se você tiver um objeto com 4 ou 5 atributos criar um método para validá-los não é tão ruim, mas no mundo real as coisas não são tão simples, e em muitas ocasiões você pode acabar com objetos repletos de atributos, regras e domínios específicos. E é neste momento de caos que a Bean Validation(JSR-380) vai te ajudar.

Bean Validation JSR-380

Como todas as API's do java, ela possui uma especificação, que pode ser consultada no link acima, e uma implementação padrão, no caso, o Hibernate Validator.

Na prática

Para ilustrar, vamos considerar como exemplo uma simples aplicação de cadastro de usuários:
Image description

OBS: O código-fonte completo do exemplo está disponível no Github

O usuário acessa uma URl para realizar seu cadastro (sign-in), fornecendo os seguintes dados:

  • userName
  • email
  • confirmEmail
  • password
  • confirmPassword

E as regras de validação para o cadastro são:

  1. Nenhum dado pode ser null e nem vazio.
  2. O email precisa ser único.
  3. O email precisa ser válido.
  4. O userName precisa ser único.
  5. O usuário precisa confirmar o email.
  6. O usuário precisa confirmar o password.
  • Se o cadastro for bem sucedido, um registro para o usuário é criado e o sistema retorna o código HTTP 201.
  • Caso alguma validação não passe, nenhum registro é criado e o sistema retorna o código HTTP 400.

Vamos utilizar o Apache Maven como gerenciador do ciclo de vida e dependências. As dependências para a Bean Validation são as seguintes:
Image description

Para a entrada de dados, vamos utilizar um Dto bem simples:
Image description

A Bean Validation funciona através de annotations, e com elas vamos garantir as regras de campos não nulos, vazios e emails:

  • NotNull
  • NotEmpty
  • NotBlank
  • Email

Image description

Note que para cada annotation também podemos definir uma mensagem padrão. Essa mensagem será retornada pelo Validator.

Porém, para que o Dto seja realmente validado, precisamos informar ao Spring, e fazemos isso no controlador usando a anotação @Valid:

Image description

Os erros de validação podem ser interceptados em tempo de execução e devidamente tratados:
Image description

Com isso já possuímos uma validação básica, contudo, existem situações mais específicas, onde somente as anotações padrão não bastam.

Customizando os validadores

Um dos nossos requisitos é bem específico:

2. O email precisa ser único.

Nesse caso, será necessário um validador exclusivo. Para tal, vamos criar uma anotação que vai executar uma classe de validação customizada:

Image description

  • Na linha 10 definimos o alvo desse validador, no caso, um campo: ElementType.Field.
  • Na linha 11 definimos que essa anotação será acessada em Runtime.
  • Na linha 12 temos o trecho mais importante, onde definimos a classe concreta que conterá a lógica para a validação de dados: EmailAlreadyExistsValidator.class:

Image description

Note que na classe de implementação também definimos qual interface será utilizada.

O método isValid será chamado pela API e é onde devemos implementar nossa lógica:
Image description

Após a criação da Inteface e do Método, podemos então anotar no Dto diretamente no campo em que vamos utilizar:

Image description

Ordem de validação e validation Groups

Podemos também definir em qual ordem as validações serão executadas, principalmente, quando temos muitas validações a serem realizadas.

Para tal, devemos implementar grupos de validação e usar a anotação @GroupSequence para definir a ordem:

Image description

Além disso, em cada campo devemos definir a qual grupo ele está ligado:
Image description

Dessa forma, conseguimos garantir que a validação seja feita de forma simples, manutenível e extensível. Verifique o código-fonte para mais exemplos, inclusive a parte de testes.

Validando através do código

Em algumas situações pode ser necessário um maior controle na execução das validações, como por exemplo, quando necessitamos capturar as mensagens de erro durante um processamento sem interrompê-lo.

Nesse caso, devemos chamar programaticamente a API.
Considere a seguinte classe:
Image description

Ao invés de chamar automaticamente a validão no controlador com o @Valid, vamos criar um método no service e dentro dele chamaremos a validação:
Image description

No método validate utilizamos um ValidationFactory para obter o validador e então chamar a validação:
Image description

E para testar a validação:
Image description

Dessa forma obtemos mais flexibilidade nas situações onde precisamos de um maior controle.

E chegamos ao final! Espero que o artigo possa te ajudar no seu dia-a-dia, e caso queira conferir melhor o código, ele está disponível no Github. Muito Obrigado!

Top comments (0)