Skip to main content

Como implementar a validação de JavaBeans

Escrito por
feature javabeans validation

1 de maio de 2023

0 minutos de leitura

A validação de JavaBeans (Bean Validation) é um modelo de validação disponível desde o lançamento da plataforma Java Enterprise Edition 6. Ela oferece uma maneira padronizada para diferentes aplicações Java validarem dados de entrada. Em um artigo anterior, explicamos como os DTOs Java são usados em aplicações modernas para evitar vazamentos acidentais de dados.

Neste artigo, vamos criar uma nova aplicação Java e validar algumas strings de exemplo para demonstrar como funciona a validação de JavaBeans. Mas, primeiro, vamos revisar o que são Beans. 

JavaBeans são objetos Java que contêm propriedades e métodos para armazenar e transferir dados entre diferentes partes de uma aplicação Java. Beans são componentes reutilizáveis que encapsulam os dados e o comportamento de uma aplicação Java. Eles são uma forma padronizada de representar objetos, seguindo determinados padrões de projeto e convenções. 

  • JavaBeans contêm propriedades, que são variáveis de instância que representam o estado de um objeto. Essas variáveis devem ser privadas. Métodos getters e setters são usados para acessar os dados armazenados em um Bean.

  • Construtores sem argumentos são usados para criar uma instância de um Bean. Podemos adicionar construtores para oferecer diferentes maneiras de inicializá-lo.

  • JavaBeans são serializáveis, o que significa que seu estado pode ser salvo em um arquivo ou transmitido por uma rede.

  • JavaBeans seguem convenções de nomenclatura, como usar os métodos getXXX e setXXX para acessar e definir o valor das propriedades.

  • JavaBeans geralmente contêm classes BeanInfo, que fornecem informações sobre o bean para ferramentas e IDEs.

Costumamos usar JavaBeans como blocos de construção para organizar e estruturar dados em aplicações maiores. Eles normalmente contêm variáveis de instância (propriedades) e métodos getter e setter (getXXX e setXXX) para acessar os dados armazenados em um Bean. Também usamos JavaBeans para criar objetos personalizados que podem ser reutilizados em diferentes partes de uma aplicação, facilitando a manutenção e a atualização do código.

Como usar a validação de JavaBeans

Um dos principais usos dos Beans é validar entradas do usuário, especificando restrições para as propriedades de um Bean, como comprimentos mínimo e máximo, caracteres permitidos e campos obrigatórios. Em seguida, usamos essas restrições para validar os dados inseridos pelos usuários e garantir que atendam aos requisitos especificados antes de serem processados pela aplicação.

O exemplo a seguir usa o Hibernate Validator em um projeto Apache Maven. O Hibernate Validator é a implementação de referência do Bean Validation.

Como criar uma aplicação Java

Primeiro, precisamos adicionar uma dependência do Hibernate Validator ao arquivo pom.xml do Maven. Para isso, use o código abaixo:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.5.Final</version>
</dependency>

Em seguida, adicionamos a API Bean Validation como dependência no pom.xml, usando o seguinte código:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

Agora, criamos um projeto Java em um novo arquivo chamado BeanValidation.java e importamos as bibliotecas necessárias:

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Pattern;
import java.util.Set;
import javax.validation.ConstraintViolation;

Em seguida, criamos um Bean simples com uma propriedade para validar, usando o código abaixo:

public class ExampleBean {
    @NotNull
    @Size(min=2, max=10)
    private String exampleString;

//Getters
    public String getExampleString() {
        return exampleString;
    }

//Setters
    public void setExampleString(String exampleString) {
        this.exampleString = exampleString;
    }
}

Este exemplo usa as anotações @NotNull e @Size para especificar que a propriedade exampleString não pode ser nula e deve ter no mínimo dois e no máximo dez caracteres. Definimos os métodos getExampleString e setExampleStrin como getters e setters da propriedade exampleString na classe ExampleBean.

Veja como funciona o Bean Validation

Para usar a classe BeanValidation e validar o Bean, executamos o seguinte:

public class BeanValidation {
    public static void main(String[] args) {
        ExampleBean bean = new ExampleBean();
        bean.setExampleString("hello");
// Create a Validator instance using the default validation factory      
  ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
// Validate an instance of the ExampleBean class and get a set of constraint violations, if any        
Set<ConstraintViolation<ExampleBean>> violations = validator.validate(bean);
        if (!violations.isEmpty()) {
            System.out.println("Errors:");
            for (ConstraintViolation<ExampleBean> violation : violations) {
                System.out.println(violation.getMessage());
            }
        } else {
            System.out.println("Validation successful");
        }
    }
}

Como definimos o valor da string como hello, ela passa na validação. Se definirmos a propriedade exampleString com um valor que não atenda às restrições especificadas em um Bean, o método validate retornará um conjunto de objetos ConstraintViolation que descrevem os erros.

Para tratar erros quando as strings não passam na validação, criamos casos de tratamento de erros que verificam se há violações e exibem uma mensagem de erro quando isso acontece.

Confira o código completo do arquivo BeanValidation.java:

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.ConstraintViolation;

public class ExampleBean {
    @NotNull
    @Size(min=2, max=10)
    private String exampleString;

    public String getExampleString() {
        return exampleString;
    }

    public void setExampleString(String exampleString) {
        this.exampleString = exampleString;
    }
}

public class BeanValidation {
    public static void main(String[] args) {
        ExampleBean bean = new ExampleBean();
        bean.setExampleString("hello");

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        Set<ConstraintViolation<ExampleBean>> violations = validator.validate(bean);

        if (!violations.isEmpty()) {
            System.out.println("Errors:");
            for (ConstraintViolation<ExampleBean> violation : violations) {
                System.out.println(violation.getMessage());
            }
        } else {
            System.out.println("Validation successful");
        }
    }
}

Este exemplo retorna um erro se a string de entrada tiver menos de dois caracteres, mais de dez caracteres ou for nula. Se a string não atender a essas restrições, uma mensagem de erro será exibida indicando qual requisito não foi cumprido.

Veja um exemplo de restrições para validar os dados de login de um usuário com campos de e-mail e senha:

public class UserBean {
    @NotNull
    @Size(min=5, max=30)
    @Pattern(regexp = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}")
    private String email;

    @NotNull
    @Size(min=8, max=15)
    @Pattern(regexp = "((?=.*[a-z])(?=.*\\d)(?=.*[A-Z])(?=.*[@#$%!]).{8,15})")
    private String password;

}

A classe UserBean contém duas propriedades: email e password. A propriedade email garante que as entradas tenham no mínimo cinco e no máximo trinta caracteres e correspondam ao padrão de um endereço de e-mail válido. 

A propriedade password garante que a senha não seja nula, tenha no mínimo oito e no máximo quinze caracteres e contenha pelo menos uma letra minúscula, uma maiúscula, um dígito e um caractere especial. 

Entenda as restrições

As restrições são definidas por meio de anotações — tipos especiais de metadados adicionados a classes, campos e métodos Java. Podemos aplicar restrições às propriedades de uma classe Bean em diferentes lugares: diretamente à propriedade, ao método getter da propriedade ou a um parâmetro do construtor da classe.

Depois que as restrições são definidas para um Bean, a validação usa um objeto Validator da API Bean Validation. O objeto Validator verifica se uma instância do Bean atende às restrições de suas propriedades. Se um Bean violar alguma restrição, o Validator retornará um conjunto de violações, indicando quais propriedades falharam na validação e por quê.

O Bean Validation API disponibiliza algumas restrições integradas do JavaBeans, que podemos usar imediatamente. Entre elas estão @NotNull, @Size, @Pattern, @Min, @Max, @DecimalMin e@DecimalMax. Para ver a lista completa de restrições integradas, consulte a documentação do Hibernate Validator.

Restrições personalizadas são aquelas que definimos para atender a requisitos específicos de validação. Para criá-las, definimos uma anotação personalizada e implementamos um ConstraintValidator que contém a lógica de validação. 

Como criar anotações personalizadas

Para criar uma restrição personalizada para o Bean Validation, precisamos:

  • Criar uma classe de anotação personalizada e anotá-la com @Constraint. Isso indica que a classe anotada representa uma restrição personalizada.

  • Implementar a lógica de validação em uma classe que implemente a interface ConstraintValidator. A classe deve ter parâmetros para a anotação da restrição personalizada e para o tipo de elementos que ela pode validar.

  • Registrar a restrição personalizada adicionando uma entrada no arquivo XML de configuração da validação ou anotando a classe da restrição personalizada com @Constraint(validatedBy=<Validator class>).

Veja um exemplo de restrição personalizada chamada ValidSearchTerm:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

@Documented
@Constraint(validatedBy = ValidSearchTermValidator.class)
@Target({ FIELD })
@Retention(RUNTIME)
public @interface ValidSearchTerm {

    String message() default "Search term contains invalid characters";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Em seguida, podemos implementar a lógica de validação que usa expressões regulares para criar a restrição. Neste caso, queremos uma string de busca alfanumérica comum, sem caracteres especiais:

public class ValidSearchTermValidator implements ConstraintValidator<ValidSearchTerm, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        return value.matches("[A-Za-z0-9]+");
    }
}

Depois, usamos a restrição personalizada em um Bean desta forma:

public class SearchBean {
    @ValidSearchTerm
    private String searchTerm;

    public String getSearchTerm() {
        return searchTerm;
    }

    public void setSearchTerm(String searchTerm) {
        this.searchTerm = searchTerm;
    }
}

Considerações finais sobre Bean Validation

O Bean Validation oferece uma maneira unificada e consistente de validar dados em aplicações Java, facilitando a criação e a manutenção de código que garante o processamento seguro dos dados. Com esse modelo, podemos economizar o tempo e o esforço que seriam necessários para escrever uma lógica de validação personalizada.

Com o Bean Validation, podemos especificar restrições para as propriedades de um JavaBean usando anotações. Elas podem ser integradas ou personalizadas e definem os requisitos que as entradas dos usuários devem atender para serem consideradas válidas. Em seguida, o modelo usa essas restrições para validar o Bean e identificar possíveis erros.

O Bean Validation também permite tratar erros durante a validação. O framework retorna uma lista de violações de restrições, e podemos usar essas informações para dar um retorno específico ao usuário. Isso ajuda a melhorar a experiência do usuário e torna a aplicação mais robusta e segura.

Em resumo, o Bean Validation é uma ferramenta essencial para garantir a qualidade e a segurança de aplicações Java. Seguindo as práticas recomendadas desse modelo, podemos criar aplicações bem projetadas, fáceis de manter e seguras.

Comece a participar de desafios de Capture the Flag

Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.