ValidRolesValidator.java
package com.albertsilva.dev.asjcatalog.validation.role.validator;
import java.util.Set;
import com.albertsilva.dev.asjcatalog.repository.RoleRepository;
import com.albertsilva.dev.asjcatalog.validation.role.annotation.ValidRoles;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* Validator de {@link ValidRoles}, aplicado a {@code Set<Long>} com ids de
* roles.
*
* <p>
* <b>Comportamento:</b> {@code null} ou conjunto vazio ⇒ <b>válido</b>. Caso
* contrário, chama {@code RoleRepository.existsById} para cada id (uma
* consulta por id, interrompendo no primeiro inexistente); se algum não
* existir, registra {@code {role.invalid}} sem nó de propriedade (fica no
* campo anotado). Como o tipo é {@link Set}, ids duplicados não existem no
* objeto (a desserialização os colapsa) e a ordem é irrelevante. Um elemento
* {@code null} dentro do conjunto faria {@code existsById} lançar exceção (a
* confirmar em testes).
* </p>
*
* <p>
* <b>Relação com {@code UserService}:</b> este validator aceita {@code null} e
* vazio; o service trata {@code null} como "manter as roles" na atualização e
* "sem roles" na criação, e conjunto vazio como "remover todas" na atualização
* e "sem roles" na criação. O service ainda compara a quantidade de roles
* encontradas com a de ids recebidos (validação repetida).
* </p>
*/
public class ValidRolesValidator implements ConstraintValidator<ValidRoles, Set<Long>> {
/** Repositório usado para verificar a existência de cada role. */
private final RoleRepository repository;
/**
* @param repository repositório de roles, injetado pelo Spring
*/
public ValidRolesValidator(RoleRepository repository) {
this.repository = repository;
}
/**
* Verifica se todos os ids informados existem como role.
*
* @param value ids de roles (pode ser {@code null} ou vazio)
* @param context contexto usado para registrar a violação {@code role.invalid}
* @return {@code true} se for nulo/vazio ou se todos os ids existirem
*/
@Override
public boolean isValid(Set<Long> value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty()) {
return true;
}
boolean allRolesExist = value.stream().allMatch(repository::existsById);
if (allRolesExist) {
return true;
}
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("{role.invalid}").addConstraintViolation();
return false;
}
}