Introdução ao Bean Validation: Deixe o Java Trabalhar!
Tags: java, validation, portuguese, spring
Published: 2021-11-01 22:15:57

---
title: Introdução ao Bean Validation: Deixe o Java Trabalhar!
published: true
description: Aprenda a validar seus beans com o framework de validação do java (JSR 380)
tags: #java #validation #portuguese #spring
//cover_image: https://direct_url_to_image.jpg
---
## 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.
<center>
![Validação manual](https://dev-to-uploads.s3.amazonaws.com/i/w49kmjosmbewr34ox4ed.PNG)
######Típica validação manual
</center>

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](https://beanvalidation.org/2.0-jsr380/)

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](Hibernate Validator).

## Na prática 
Para ilustrar, vamos considerar como exemplo uma simples aplicação de cadastro de usuários:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38oq9w0dsd6r5vdd508w.png)

*OBS: O código-fonte completo do exemplo está disponível no [Github](https://github.com/alabvix/ubaseapi)*

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q43a6xs0jg4qds022qbg.png) 

Para a entrada de dados, vamos utilizar um Dto bem simples:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2r50utgr5srah7s2eny.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc3lhvcpkudau9ae0w5z.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wni3p0o4v6if524r9eh.png)

Os erros de validação podem ser interceptados em tempo de execução e devidamente tratados:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q8hxf0p99emwsek0bb5z.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4c647th22qn9c3a9p10.png)
- 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2eqo9ws1xkwuhps51abm.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k10dlo44qtotkv781nua.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rih8sapcn4wd1hz7fg9w.png)

##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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/orgfyqyhev7a1vbyjhwy.png)
 
Além disso, em cada campo devemos definir a qual grupo ele está ligado:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57r6im39ahcetsug3rl8.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ouqlhvtya4tg26qv6e40.png)
 
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6hkpgfxmk0v9maohsxzm.png)

No método **validate** utilizamos um ValidationFactory para obter o validador e então chamar a validação:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofkpz4zlcaeee3438je6.png)

E para testar a validação:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hpymeguonqb2reoawb22.png)

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](https://github.com/alabvix/ubaseapi)**. Muito Obrigado!