Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

[Dúvida] Usar o mesmo validador nos contextos de inclusão e de alteração

Olá, pessoal

Pautado na ideia de "Lista de Validadores" dessa aula, estava pensando numa forma de se aproveitar alguns validadores em contexto distintos.

Por exemplo, vamos imaginar a classe de domínio "MOTORISTA" (tabela motoristas no banco de dados), para a qual criei os records "CriacaoMotoristaDto" e "AlteracaoMotoristaDto":

public record CriacaoMotoristaDto (
        Integer id,

        @NotNull
        String cdCpfMotorista,

        @NotNull
        @JsonFormat(pattern = "dd/MM/yyyy")
        LocalDate dtNascimento,

        @NotBlank
        String nmMotorista,
        
        @NotNull
        String cdCnhMotorista,
        
        @NotBlank
        String cdCategoriaCnhMotorista,
        
        @NotNull
        Boolean exerceAtividadeRemunerada,

        @Not Null
        @JsonFormat(pattern = "dd/MM/yyyy")
        LocalDate dtValidadeCnhMotorista
) {}
public record AlteracaoMotoristaDto (
        @NotNull
        Integer id,

        String cdCpfMotorista,

        @JsonFormat(pattern = "dd/MM/yyyy")
        LocalDate dtNascimento,

        String nmMotorista,
        
        String cdCnhMotorista,
        
        String cdCategoriaCnhMotorista,

        Boolean exerceAtividadeRemunerada,

        @JsonFormat(pattern = "dd/MM/yyyy")
        LocalDate dtValidadeCnhMotorista
) {}

Na inclusão de motorista, todos os campos são preenchidos.
Na alteração de motorista, serão preenchidos apenas os campos que se desejam alterar, omitindo aqueles que se deseja manter o conteúdo já armazenado. Contudo, a validação deve ser feita na totalidade para que a nova informação seja compatível com as demais.
Um dado motorista pode receber a condição de "Exercer atividade remunerada", mas para que esta mudança seja aceita, a Data de Validade da CNH presente na base ainda esteja vigente, por exemplo.

public class MotoristaService {

    @Autowire
    private List<ValidadorNovoMotorista> validadoresNovo;
    @Autowire
    private List<ValidadorMotoristaExistente> validadoresExistente;
    
    public void cadastrar(CriacaoMotoristaDto dados) {
        
        validadoresNovo.forEach(v -> v.validar(dados);
        
        // demais procedimentos para "Inclusão de Novo Motorista"
    }
    
    public void alterar(AlteracaoMotoristaDto dados) {
        
        validadoresExistente.forEach(v -> v.validar(dados);
        
        // demais procedimentos para "Alteração de Motorista Existente"

    }
}

Como seria possível para o mesmo validador seja reaproveitado, sem duplicar?

public class ValidadorDataValidadeCnh implements ValidadorNovoMotorista, ValidadorMotoristaExistente{

    public void validar(????????????? dados) {      // Qual seria o tipo?
        if(dados.dtValidadeCnhMotorista.isBefore(LocalDate.now())) {
            throw new ValidacaoException("Data de Validade CNH está expirada.");
    }
    
}	
1 resposta
solução!

Olá! Tudo bem?

A solução para isso é usar uma interface comum para ambos os validadores e, assim, permitir que a mesma lógica de validação seja aplicada em diferentes cenários.

Você pode criar uma interface, por exemplo, ValidadorMotorista, que será implementada por todos os validadores que você deseja compartilhar entre os contextos de criação e alteração. Veja como você pode fazer isso:

  1. Crie uma interface comum:
public interface ValidadorMotorista {
    void validar(Object dados);
}
  1. Implemente a interface nos validadores:
@Component
public class ValidadorDataValidadeCnh implements ValidadorMotorista {

    @Override
    public void validar(Object dados) {
        LocalDate dtValidadeCnhMotorista;
        
        if (dados instanceof CriacaoMotoristaDto) {
            dtValidadeCnhMotorista = ((CriacaoMotoristaDto) dados).dtValidadeCnhMotorista();
        } else if (dados instanceof AlteracaoMotoristaDto) {
            dtValidadeCnhMotorista = ((AlteracaoMotoristaDto) dados).dtValidadeCnhMotorista();
        } else {
            throw new IllegalArgumentException("Tipo de dados não suportado");
        }

        if (dtValidadeCnhMotorista.isBefore(LocalDate.now())) {
            throw new ValidacaoException("Data de Validade CNH está expirada.");
        }
    }
}
  1. Injete e use a lista de validadores na sua classe de serviço:
@Autowired
private List<ValidadorMotorista> validadores;

public void cadastrar(CriacaoMotoristaDto dados) {
    validadores.forEach(v -> v.validar(dados));
    // demais procedimentos para "Inclusão de Novo Motorista"
}

public void alterar(AlteracaoMotoristaDto dados) {
    validadores.forEach(v -> v.validar(dados));
    // demais procedimentos para "Alteração de Motorista Existente"
}

Com essa abordagem, você pode reutilizar o mesmo validador para diferentes tipos de DTOs, desde que eles compartilhem os campos necessários para a validação. A interface ValidadorMotorista permite que você padronize o método validar, e o uso do polimorfismo com instanceof permite que você trate diferentes tipos de dados conforme necessário.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.