0Pricing
Java Academy · Aula

Anotações de restrição personalizadas

Crie uma anotação @UniqueEmail personalizada com uma implementação de ConstraintValidator.

Anotações de restrição personalizadas é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

Quando as restrições padrão não são suficientes

As anotações padrão de validação de beans abrangem casos comuns. Para regras específicas do domínio (por exemplo, e-mail exclusivo, IBAN válido ou força da senha), crie anotações de restrição personalizadas.

Definindo a anotação de restrição

Crie uma anotação com @Constraint(validatedBy = ...), os elementos obrigatórios message, groups e payload, além da retenção e do alvo apropriados.

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Documented
@Constraint(validatedBy = UniqueEmailValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
    String message() default "Email already registered";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Implementando ConstraintValidator

Implemente ConstraintValidator<UniqueEmail, String>. O método initialize lê os elementos da anotação; isValid realiza a verificação propriamente dita.

@Component
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
    @Autowired private UserRepository repo;
    @Override
    public boolean isValid(String email, ConstraintValidatorContext ctx) {
        if (email == null) return true; // let @NotBlank handle null
        return !repo.existsByEmail(email);
    }
}

Usando a restrição personalizada

Aplique a anotação como qualquer restrição padrão a um campo, parâmetro ou valor de retorno.

public record CreateUserRequest(
    @NotBlank
    String name,
    @NotBlank @Email @UniqueEmail
    String email
) {}

Mensagem personalizada com interpolação

Faça referência aos elementos da anotação na mensagem usando {elementName}. Use ctx.buildConstraintViolationWithTemplate() para adicionar mensagens personalizadas com dados dinâmicos.

@Constraint(validatedBy = RangeValidator.class)
public @interface InRange {
    int min() default 0;
    int max() default 100;
    String message() default "Must be between {min} and {max}";
    // ...
}

Restrição no nível da classe

Aplique uma restrição no nível da classe para validar vários campos em conjunto — útil para regras entre campos, como a confirmação de senha.

@Documented
@Constraint(validatedBy = PasswordMatchValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PasswordMatch {
    String message() default "Passwords do not match";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Implementação de um validador no nível da classe

O validador recebe o objeto inteiro. Acesse vários campos para realizar a validação entre campos.

public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, ChangePasswordRequest> {
    public boolean isValid(ChangePasswordRequest req, ConstraintValidatorContext ctx) {
        if (req.getNewPassword() == null) return true;
        boolean match = req.getNewPassword().equals(req.getConfirmPassword());
        if (!match) {
            ctx.disableDefaultConstraintViolation();
            ctx.buildConstraintViolationWithTemplate("Passwords do not match")
               .addPropertyNode("confirmPassword").addConstraintViolation();
        }
        return match;
    }
}

Compondo restrições

Crie uma metarrestrição anotando sua anotação personalizada com restrições existentes. Ambas serão aplicadas automaticamente.

@NotBlank
@Email
@Size(max = 255)
@Constraint(validatedBy = {})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidEmail {
    String message() default "Invalid email";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Retornando várias violações

Use ctx.disableDefaultConstraintViolation() e adicione mensagens de violação individuais para cada problema encontrado em uma única execução do validador.

public boolean isValid(String password, ConstraintValidatorContext ctx) {
    List<String> issues = new ArrayList<>();
    if (password.length() < 8) issues.add("Too short");
    if (!password.matches(".*\\d.*")) issues.add("Must contain a digit");
    if (issues.isEmpty()) return true;
    ctx.disableDefaultConstraintViolation();
    issues.forEach(msg -> ctx.buildConstraintViolationWithTemplate(msg).addConstraintViolation());
    return false;
}

Validadores gerenciados pelo Spring

Como UniqueEmailValidator é anotado com @Component, o Spring injeta repositórios nele. Isso só funciona se o validador for inicializado por meio do validador do Spring, que o Spring Boot configura automaticamente.

Testes de validadores personalizados

Teste os validadores diretamente — não é necessário um contexto do Spring para a lógica de validação pura. Use Validation.buildDefaultValidatorFactory() para testes de integração.

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
CreateUserRequest req = new CreateUserRequest("", "bad-email", null);
Set<ConstraintViolation<CreateUserRequest>> violations = validator.validate(req);
System.out.println(violations.size()); // 3

Verificação rápida

Qual interface um validador de restrições personalizado implementa?

Recapitulação

Crie @interface com @Constraint(validatedBy=...). Implemente ConstraintValidator. Use @Component para a injeção do Spring. As restrições no nível da classe validam vários campos em conjunto. Componha restrições existentes para evitar duplicação.

Perguntas Frequentes

A aula “Anotações de restrição personalizadas” é grátis?

Sim — o texto completo de “Anotações de restrição personalizadas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Anotações de restrição personalizadas”?

Crie uma anotação @UniqueEmail personalizada com uma implementação de ConstraintValidator. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Anotações de restrição personalizadas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Validação de beans: @NotNull, @Size, @Pattern
  2. Anotações de restrição personalizadas
  3. Tratamento global de exceções com @ControllerAdvice
  4. Detalhes de problemas RFC 7807 e respostas de erro consistentes
← Voltar para Java Academy