Este artigo faz parte da série “Quarkus for Spring Developers”.

Validar dados é uma tarefa que ocorre em todas as camadas, da apresentação à persistência. Se você ainda faz isso com dezenas de blocos if (obj.getCampo() == null), sua aplicação sofre de um “acoplamento de validação” que torna o código difícil de ler e propenso a erros. No ecossistema Java moderno, utilizamos o Jakarta Bean Validation 3.1, com o Hibernate Validator 9.1 como implementação de referência.

Neste guia detalhado, vamos transformar sua forma de validar dados, indo desde anotações básicas até validação de métodos e documentos brasileiros.


1. Evolução do Sistema: DTOs e Validação Recursiva

Seguindo nosso projeto de Pedidos iniciado nos artigos anteriores, agora usamos DTOs para proteger nossas entidades. A anotação @Valid em listas é o que permite a validação “em cascata”.

OrderItemDTO.java

public class OrderItemDTO {
    @NotBlank(message = "Código do produto é obrigatório")
    public String productCode;

    @Positive(message = "A quantidade deve ser maior que zero")
    public int quantity;
}

OrderDTO.java

public class OrderDTO {
    @NotBlank(message = "O nome do cliente é obrigatório")
    public String customerName;

    @NotEmpty(message = "O pedido deve ter pelo menos um item")
    public List<@Valid OrderItemDTO> items; // @Valid ativa a validação nos objetos da lista

    @PositiveOrZero(message = "O total não pode ser negativo")
    public double totalAmount;
}

No seu Resource JAX-RS (Quarkus REST):

@POST
public Response create(@NotNull @Valid OrderDTO order) {
    // Se o código chegar aqui, os dados estão 100% validados!
    return Response.status(Response.Status.CREATED).entity(order).build();
}

2. O Coração da Validação: Maven e Quarkus CLI

Diferente do Spring Boot, onde a validação muitas vezes vem em starters genéricos, no Quarkus somos explícitos para garantir que o binário final (especialmente em modo Nativo com GraalVM) seja otimizado.

No Quarkus (Extensão Otimizada)

Para adicionar o suporte ao Hibernate Validator:

quarkus ext add hibernate-validator

Isso adiciona a dependência io.quarkus:quarkus-hibernate-validator ao seu pom.xml, que já configura o motor EL e a integração com CDI automaticamente.

Em Projetos Java Puros (Standalone)

O Bean Validation é agnóstico a framework. Para usá-lo em uma biblioteca ou CLI sem Quarkus/Spring, você precisa da implementação e de um motor de Jakarta Expression Language (EL) para processar as mensagens dinâmicas.

<dependencies>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>9.1.0.Final</version>
    </dependency>
    <!-- Necessário para Pure Java processar variáveis como {min} nas mensagens -->
    <dependency>
        <groupId>org.glassfish.expressly</groupId>
        <artifactId>expressly</artifactId>
        <version>6.0.0</version>
    </dependency>
</dependencies>

3. O Arsenal de Defesa: Tabela de Anotações Essenciais

As anotações abaixo são o núcleo da especificação. Elas permitem que você descreva o que deve ser validado diretamente no modelo.

AnotaçãoDescriçãoExemplo
@NotNullO campo não pode ser nulo.@NotNull String id;
@NotEmptyNão nulo e tamanho > 0 (Strings, Collections, Mapas).@NotEmpty List<@Valid Item> items;
@NotBlankString não nula e com pelo menos um caractere real.@NotBlank String name;
@SizeDefine limites de tamanho para Strings ou coleções.@Size(min = 3, max = 50)
@Min / @MaxLimites numéricos inclusivos.@Min(18) int age;
@Positive / @PositiveOrZeroO valor deve ser maior que 0 (ou >= 0).@Positive double price;
@Negative / @NegativeOrZeroO valor deve ser menor que 0 (ou <= 0).@Negative double debt;
@DecimalMin / @DecimalMaxLimites decimais em formato String.@DecimalMin("0.01")
@EmailValida o formato de e-mail (RFC compliant).@Email String email;
@Past / @PastOrPresentDatas no passado (ex: nascimento).@Past LocalDate birthday;
@Future / @FutureOrPresentDatas no futuro (ex: entrega).@Future LocalDateTime delivery;
@DigitsValida número de dígitos inteiros e frações.@Digits(integer=5, fraction=2)
@PatternValida contra uma Expressão Regular (Regex).@Pattern(regexp = "^[A-Z0-9]+$")
@AssertTrue / @AssertFalseValida o estado de um booleano.@AssertTrue boolean accepted;

Interpolação de Mensagens

Você pode usar variáveis da própria anotação nas mensagens:

@Size(min = 2, max = 14, message = "A placa '${validatedValue}' deve ter entre {min} e {max} caracteres")
private String licensePlate;

4. Validações Brasileiras (Pacote BR)

O Hibernate Validator possui suporte nativo ao mercado brasileiro através do pacote org.hibernate.validator.constraints.br. Isso valida não apenas o formato, mas o algoritmo dos dígitos verificadores.

  • @CPF: Valida o Cadastro de Pessoa Física.
  • @CNPJ: Valida o Cadastro Nacional da Pessoa Jurídica (Suporta o novo formato alfanumérico de 2026).
  • @TituloEleitoral: Valida o número do Título de Eleitor brasileiro.
import org.hibernate.validator.constraints.br.CPF;
import org.hibernate.validator.constraints.br.CNPJ;

public class CompanyDTO {
    @CNPJ(message = "CNPJ inválido")
    public String cnpj;
    
    @CPF(message = "CPF do responsável inválido")
    public String managerCpf;
}

5. Validação de Métodos: Pré e Pós-condições

Poucos desenvolvedores sabem, mas você pode validar os parâmetros e o retorno de qualquer método CDI. Isso é excelente para impor regras de negócio na camada de serviço.

@ApplicationScoped
public class OrderService {

    public void processOrder(
        @NotNull @Valid OrderDTO order, 
        @Positive int priority
    ) {
        // Lógica...
    }

    @NotNull @Size(min = 1)
    public List<Order> listRecentOrders() {
        return repository.findAll();
    }
}

Se uma regra for violada, o Quarkus lançará uma ConstraintViolationException.


6. Criando sua Própria Regra: Validação Customizada

Quando as anotações padrão não bastam, criamos a nossa. No Quarkus, os validadores são beans CDI, permitindo injetar repositórios.

Passo 1: A Anotação

@Target({ FIELD, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = CustomerExistsValidator.class)
public @interface CustomerExists {
    String message() default "Cliente não encontrado";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Passo 2: O Validator

@ApplicationScoped
public class CustomerExistsValidator implements ConstraintValidator<CustomerExists, Long> {
    @Inject CustomerRepository repository;

    @Override
    public boolean isValid(Long id, ConstraintValidatorContext context) {
        if (id == null) return true; // Deixe @NotNull cuidar da obrigatoriedade
        return repository.findById(id) != null;
    }
}

7. Atributos Avançados: Groups e Payload

  • Groups (Grupos): Permite validar partes diferentes do objeto em momentos diferentes. Ex:
    public interface OnCreate {}
    public interface OnUpdate {}
    
    public class User {
        @Null(groups = OnCreate.class)
        @NotNull(groups = OnUpdate.class)
        public Long id;
    }
    
  • Payload: Serve para carregar metadados. Útil para definir severidade:
    @NotNull(payload = Severity.Error.class)
    public String criticalField;
    

8. Usando Bean Validation sem Framework (Pure Java)

Você pode usar o motor de validação manualmente, o que é útil em testes de unidade ou scripts:

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

Set<ConstraintViolation<OrderDTO>> violations = validator.validate(myOrder);
if (!violations.isEmpty()) {
    violations.forEach(v -> System.out.println(v.getMessage()));
}

Dica de Senior: Annotation Processor

Para evitar erros bobos como colocar @Past em uma variável do tipo int, adicione o Hibernate Validator Annotation Processor ao seu projeto. Ele transformará esses erros em falhas de compilação.

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>9.1.0.Final</version>
</dependency>

Conclusão

Bean Validation é a forma profissional de garantir a integridade dos seus dados sem poluir o código com if-else. No Quarkus, essa ferramenta ganha performance extra graças às otimizações de build time. Pare de escrever validações manuais e deixe o motor do Jakarta trabalhar por você!


Recursos