Olá Pessoal, tudo bom?
O post de hoje é relacionado a criação de um projeto básico em Java utilizando o controlador de dependências de bibliotecas Maven e adicionando a especificação Bean Validation junto. Utilizaremos o post básico de criação de um projeto Maven, assim iremos continuar o projeto lá criado. Além disso descrevei um pouco sobre o Bean Validation. Veja na continuação desse post…
Bean Validation – definição
A Bean Validation, também conhecida como a especificação JSR 303, tem seu criador Emmanuel Bernard, que atualmente é responsável por 4 projetos do Hibernate: Annotations, EntityManager, Validator, and Hibernate Search. O Hibernate Validator é a implementação oficial da especificação do Bean Validation.
Validação de dados é uma tarefa básica que ocorre em praticamente todas as camadas de uma aplicação, da interface com o usuário até a persistência dos dados. Uma coisa comum que ocorre é que a lógica de validação é realizada em diversos pontos dessas camadas, consumindo tempo e aumentando o riscos de erros, além de muitas vezes a duplicação de código. Para evitar essa duplicação, alguns grupos de desenvolvimento começaram a colocar parte dessa lógica de validação direto na camada Model, fazendo com que a própria entidade se validade. Mas por que a camada Model? Porque essa camada praticamente permeia todas as outras camadas na execução de uma aplicação.
As funcionalidades do Bean Validation são:
- Prover annotations para a validação de dados básicos
- Prover annotations para a validação de métodos
- Criação de mensagens próprias para essas validações
- Criar suas próprias annotations de validação
- Criar grupos de annotations de validação
Então oBean Validation é uma especificação robusta que auxilia na validação de informações em projeto Java.
Uma especificação nunca é implementada ao pé da letra, apenas é criada para que outros vendors possam implementar bibliotecas seguindo esse padrão, isso ajuda na hora de trocar de uma biblioteca para outra. No nosso caso utilizaremos o Hibernate Validator, que implementa esse padrão, pois é a implementação padrão da Especificação.
Incluindo Bean Validation em um Projeto Básico no Eclipse
O primeiro ponto é criar o projeto básico do Maven conforme o post relacionado.
Depois de criado, é hora de começar a adaptação nos arquivos desse projeto a fim de utilizar o Bean Validation.
Alterando o pom.xml
Abra o arquivo pom.xml, que se encontra na raiz do projeto. Adicione a dependência do Hibernate Validator, biblioteca que implementa a especificação Bean Validation. Vamos adicionar a ultima versão estável, Bean Validation 1.1, mas até o fim do ano de 2017 irá sair a nova versão da Bean Validation a 2.0. O código destacado abaixo acrescenta essa dependência:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.4.Final</version> </dependency> </dependencies> |
Alem disso, o Hibernate Validator necessita de uma implementação da JSR 341 – Unified Expression Language, para as expressões dinâmicas nas mensagens de violation. Quando rodamos a aplicação em um container JEE, como o JBoss Wild Fly, uma implementação da JSR 341 existe dentro do container. Mas em um ambiente JSE é necessário adicionarmos essa dependência no arquivo pom.xml. O código destacado abaixo acrescenta essa dependência:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.4.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b08</version> </dependency> </dependencies> |
Pronto, com esses códigos o maven irá adicionar a depedência do Bean Validation ao projeto. Agora vamos alterar outros pontos para poder testar essa dependência.
Criação de um package dominio
Dentro de um projeto normalmente existem classes que são utilitárias a todo o sistema, para padronizar iremos criar um sub-package chamado dominio, embaixo do package SeminariosCientificos. Se você não sabe como criar um package dê uma olhada aqui.
Criação de uma Entity de Teste
A fim de conseguir testar o Bean Validation iremos criar uma classe Usuario dentro do novo package dominio. Essa classe irá conter 4 atributos, nome, testes, sobre e idade, com suas respectivas validações. O código da classe Usuario está abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package br.com.mauda.SeminariosCientificos.dominio; import javax.validation.constraints.AssertTrue; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class Usuario { @NotNull(message = "Nome não pode ser nulo") private String nome; @AssertTrue private boolean testes; @Size(min = 10, max = 20, message = "O campo Sobre deve ter entre 10 e 20 caracteres") private String sobre; @Min(value = 18, message = "Idade não pode ser menor que 18") @Max(value = 150, message = "Idade não pode ser maior que 150") private int idade; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public boolean isTestes() { return testes; } public void setTestes(boolean testes) { this.testes = testes; } public String getSobre() { return sobre; } public void setSobre(String sobre) { this.sobre = sobre; } public int getIdade() { return idade; } public void setIdade(int idade) { this.idade = idade; } } |
Alteração da classe App
A classe App já criada anteriormente pelo Maven, deverá ser alterada, pois não realiza o teste necessário para o Bean Validation. As seguintes alterações deverão ser realizadas:
- Acrescentar os imports das linhas 3 a 12;
- Remover a linha System.out.println( “Hello World!” );
- Em seu lugar acrescentar as linhas 20 a 27 do código que servem para criar novas instâncias da classe Usuario;
- Criar o método validar(Object) referenciado nas linhas 30 a 48;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package br.com.mauda.SeminariosCientificos; import java.util.HashSet; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.UnexpectedTypeException; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import br.com.mauda.SeminariosCientificos.dominio.Usuario; /** * Hello world! * */ public class App { public static void main(String[] args) { Usuario user = new Usuario(); validar(user); user = new Usuario(); user.setTestes(true); user.setSobre("Isso é tudo"); user.setIdade(50); validar(user); } public static void validar(Object object){ Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>>(); ValidatorFactory dfv = Validation.buildDefaultValidatorFactory(); Validator validator = dfv.getValidator(); try { violations.addAll(validator.validate(object)); } catch (UnexpectedTypeException cause) { } if(!violations.isEmpty()){ System.err.println("\n\n\nErros de Validação: "); } for (ConstraintViolation<?> violation : violations) { System.err.println(violation.getMessage()); } } } |
É interessante observar que criamos uma ValidatorFactory e um Validator para realizar as validações nos objetos passados como parâmetros ao método validar. Essa validação é realizada no método validate() da classe Validator.
Alteração da classe AppTest
A classe AppTest já criada anteriormente pelo Maven, deverá ser alterada, pois não realiza o teste necessário para o Bean Validation. As seguintes alterações deverão ser realizadas:
- Remoção de todos os testes unitários anteriores;
- Adição dos atributos Validator (static) e usuario;
- Adição do método BeforeClass;
- Adição de sete métodos de teste;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
package br.com.mauda.SeminariosCientificos; import static org.junit.Assert.assertEquals; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import br.com.mauda.SeminariosCientificos.dominio.Usuario; /** * Unit test for simple App. */ public class AppTest{ private static Validator validator; private Usuario usuario; @BeforeClass public static void setUpValidator() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } @Before public void init(){ this.usuario = new Usuario(); this.usuario.setNome("Valor"); this.usuario.setTestes(true); this.usuario.setSobre("Isso é tudo"); this.usuario.setIdade(50); } @Test public void valido() { Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals( 0, constraintViolations.size() ); } @Test public void nomeNull() { this.usuario.setNome(null); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("Nome não pode ser nulo", constraintViolations.iterator().next().getMessage()); } @Test public void testesFalse() { this.usuario.setTestes(false); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("deve ser verdadeiro", constraintViolations.iterator().next().getMessage()); } @Test public void sobreMinimo() { this.usuario.setSobre("012345678"); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("O campo Sobre deve ter entre 10 e 20 caracteres", constraintViolations.iterator().next().getMessage()); } @Test public void sobreMaximo() { this.usuario.setSobre("0123456789 0123456789"); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("O campo Sobre deve ter entre 10 e 20 caracteres", constraintViolations.iterator().next().getMessage()); } @Test public void idadeMinimo() { this.usuario.setIdade(17); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("Idade não pode ser menor que 18", constraintViolations.iterator().next().getMessage()); } @Test public void idadeMaximo() { this.usuario.setIdade(151); Set<ConstraintViolation<Usuario>> constraintViolations = validator.validate( usuario ); assertEquals(1, constraintViolations.size()); assertEquals("Idade não pode ser maior que 150", constraintViolations.iterator().next().getMessage()); } } |
Existe um teste unitário para validar cada ponto de inconsistência que pode haver na classe Usuário.
Estado do Projeto
Abaixo na Figura 01, temos as pastas e arquivos que foram criados no projeto. Utilize essa imagem para verificar se seu projeto está parecido com o da figura.
Executando a classe App
Clique na classe App com o botão direito do mouse, vá em run > Java Application e o java irá executar o método main da classe App. Caso esteja tudo certo irá aparecer as seguintes mensagens do console da aplicação:
1 2 3 4 5 6 7 8 9 10 |
abr 03, 2017 4:33:34 PM org.hibernate.validator.internal.util.Version <clinit> INFO: HV000001: Hibernate Validator 5.3.4.Final Erros de Validação: Nome não pode ser nulo Idade não pode ser menor que 18 deve ser verdadeiro Erros de Validação: Nome não pode ser nulo |
Ignore as primeiras linhas, o que importa para nosso teste é a partir da quarta linha. No caso os erros de validação da primeira instância de Usuario, o qual praticamente tudo é nulo. No segundo grupo as validações para a instância de Usuario que só não possui o nome.
Executando a classe AppTest
A classe AppTest possui métodos que verificam a quantidade de erros retornados e suas mensagens. Esse teste ao rodar tem que dar verde, visto que a classe Usuario possui as validações corretas. Esse teste foi construído para rodar na ferramenta JUnit. Caso não conheça a ferramenta há um tutorial aqui.
finally{
Em posts futuros irei descrever melhor as constraints de validação (annotations) e outros aspectos do Bean Validation
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Leave a Reply