Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

[Bug] Erro ao tentar fazer validações

Olá!

Estou com um problema ao tentar algumas validações. As que verificam se um id de paciente e médico existem estão rodando, mas ao tentar de fato criar uma consulta ao tentar validar se o médico ou paciente estão ativos, ocorre o erro:

2024-07-12T23:53:45.262-03:00 ERROR 39357 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.ClassCastException: class med.voll.api.model.Doctor cannot be cast to class java.lang.Boolean (med.voll.api.model.Doctor is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @7836d93e; java.lang.Boolean is in module java.base of loader 'bootstrap')] with root cause

Pelo que entendi não há um erro na tentativa de conversão de um objeto do tipo Doctor para o tipo Boolean.

Segue código abaixo:

package med.voll.api.validation;

import jakarta.validation.ValidationException;
import med.voll.api.dto.appointment.AppointmentCreateDTO;
import med.voll.api.repository.DoctorRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DoctorActiveValidator implements AppointmentValidator {

    @Autowired
    private DoctorRepository doctorRepository;

    public void validate(AppointmentCreateDTO appointmentCreateDTO) {
        if (appointmentCreateDTO.doctorId() == null) {
            return;
        }

        var activeDoctor = doctorRepository.findActiveDoctorById(appointmentCreateDTO.doctorId());
        if (!activeDoctor) {
            throw new ValidationException("Médico inativo");
        }
    }
}
package med.voll.api.repository;

import med.voll.api.model.Doctor;
import med.voll.api.model.Specialty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.time.LocalDateTime;

public interface DoctorRepository extends JpaRepository<Doctor, Long> {
    Page<Doctor> findByActiveTrue(Pageable page);

    @Query("""
            SELECT d FROM Doctor d
            WHERE d.active = true
            AND d.specialty = :specialty
            AND
            d.id NOT IN (
                SELECT a.doctor.id FROM Appointment a
                WHERE a.appointmentDate = :appointmentDate
            )
            ORDER BY RAND()
            LIMIT 1
            """)
    Doctor getRandomDoctorBySpecialty(Specialty specialty, LocalDateTime appointmentDate);

    @Query("""
            SELECT d FROM Doctor d
            WHERE d.active = true
            AND d.id = :id
            """)
    Boolean findActiveDoctorById(Long id);
}
3 respostas
package med.voll.api.service;

import jakarta.validation.ValidationException;
import med.voll.api.dto.appointment.AppointmentCancelDTO;
import med.voll.api.dto.appointment.AppointmentCreateDTO;
import med.voll.api.dto.appointment.AppointmentDetailsDTO;
import med.voll.api.model.Appointment;
import med.voll.api.model.Doctor;
import med.voll.api.repository.AppointmentRepository;
import med.voll.api.repository.DoctorRepository;
import med.voll.api.repository.PatientRepository;
import med.voll.api.validation.AppointmentValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AppointmentService {

    @Autowired
    private AppointmentRepository appointmentRepository;

    @Autowired
    private DoctorRepository doctorRepository;

    @Autowired
    private PatientRepository patientRepository;

    @Autowired
    private List<AppointmentValidator> appointmentValidators;

    public AppointmentDetailsDTO createAppointment(AppointmentCreateDTO appointmentData) {
        if (appointmentData.doctorId() != null && !doctorRepository.existsById(appointmentData.doctorId())) {
            throw new ValidationException("O id do médico não foi encontrado");
        }

        if (!patientRepository.existsById(appointmentData.patientId())) {
            throw new ValidationException("O id do paciente não foi encontrado");
        }

        appointmentValidators.forEach(validator -> validator.validate(appointmentData));

        var doctor = chooseDoctor(appointmentData);
        var patient = patientRepository.findById(appointmentData.patientId()).get();

        if (doctor == null) {
            throw new ValidationException("Não há médicos disponíveis para a especialidade escolhida.");
        }
        var appointment = new Appointment(null, doctor, patient, appointmentData.appointmentDate(), null);
        appointmentRepository.save(appointment);

        return new AppointmentDetailsDTO(appointment);
    }

    private Doctor chooseDoctor(AppointmentCreateDTO appointmentData) {
        if (appointmentData.doctorId() != null) {
            return doctorRepository.getReferenceById(appointmentData.doctorId());
        }

        if (appointmentData.specialty() == null) {
            throw new ValidationException("A especialidade do médico é necessária quando não é passado um ID de médico.");
        }

        return doctorRepository.getRandomDoctorBySpecialty(appointmentData.specialty(), appointmentData.appointmentDate());
    }

    public void cancelAppointment(AppointmentCancelDTO appointmentCancelDTO) {
        if (!appointmentRepository.existsById(appointmentCancelDTO.appointmentId())) {
            throw new ValidationException("Consulta não encontrada");
        }

        var appointment = appointmentRepository.getReferenceById(appointmentCancelDTO.appointmentId());
        appointmentRepository.delete(appointment);
    }
}
solução!

Oi!

Esse seu método no repository:

 @Query("""
        SELECT d FROM Doctor d
        WHERE d.active = true
        AND d.id = :id
        """)
Boolean findActiveDoctorById(Long id);

A query está inválida e deveria ser:

@Query("SELECT d.active FROM Doctor d WHERE d.id = :id")

Valeu, Rodrigo!

Além disso, percebi que na migration eu estava definindo a coluna active como NOT NULL e isso também ocasionava problemas.

Muito obrigado