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()); // 3Verificaçã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
- Validação de beans: @NotNull, @Size, @Pattern
- Anotações de restrição personalizadas
- Tratamento global de exceções com @ControllerAdvice
- Detalhes de problemas RFC 7807 e respostas de erro consistentes