Issue
I'm developing crud application, and experiencing difficulties with springboot, which fails on startup. This is what i got:
20764 WARNING [main] --- org.springframework.context.annotation.AnnotationConfigApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'patientServiceImpl': Unsatisfied dependency expressed through method 'setPatientDAO' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'testgroup.private_clinic.dao.PatientDAO' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Screenshot of project structure:
Model:
package testgroup.private_clinic.model;
import javax.persistence.*;
@Entity
@Table(name="Patients")
public class Patient {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
@Column(name="patient_name")
String name;
@Column(name = "patient_surname")
String surname;
@Column(name = "patient_patronimic")
String patronimic;
@Column(name="adress")
String adress;
@Column(name = "status")
String status;
@Column(name="diagnosis")
String diagnosis;
//+getters and setters
Controller:
package testgroup.private_clinic.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import testgroup.private_clinic.model.Patient;
import testgroup.private_clinic.service.PatientService;
import java.util.List;
@RestController
public class PatientController {
PatientService patientService;
@Autowired
public void setPatientService(PatientService patientService){
this.patientService = patientService;
}
@RequestMapping(method = RequestMethod.GET)
public ModelAndView allPatients(){
List<Patient> patients = patientService.allPatients();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("patients");
modelAndView.addObject("patientList", patients);
return modelAndView;
}
@RequestMapping(value= "/edit{id}", method = RequestMethod.GET)
public ModelAndView editPage(@PathVariable("id") int id){
Patient patient = patientService.getByID(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
modelAndView.addObject("patient", patient);
return modelAndView;
}
@RequestMapping(value="/edit", method = RequestMethod.POST)
public ModelAndView editPatient(@ModelAttribute("patient") Patient patient){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/");
patientService.edit(patient);
return modelAndView;
}
}
Repository:
package testgroup.private_clinic.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import testgroup.private_clinic.model.Patient;
import javax.transaction.Transactional;
import java.util.*;
@Repository
public class PatientDAOImpl implements PatientDAO {
SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
@Override
@Transactional
public List<Patient> allPatients() {
Session session = sessionFactory.getCurrentSession();
return session.createQuery("from Patient").list();
}
@Override
@Transactional
public void add(Patient patient) {
Session session = sessionFactory.getCurrentSession();
session.persist(patient);
}
@Override
@Transactional
public void delete(Patient patient) {
Session session = sessionFactory.getCurrentSession();
session.delete(patient);
}
@Override
@Transactional
public void edit(Patient patient) {
Session session = sessionFactory.getCurrentSession();
session.update(patient);
}
@Override
@Transactional
public Patient getByID(int id) {
Session session = sessionFactory.getCurrentSession();
return session.get(Patient.class, id);
}
}
Service:
package testgroup.private_clinic.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import testgroup.private_clinic.model.Patient;
import testgroup.private_clinic.dao.PatientDAO;
import javax.transaction.Transactional;
import java.util.List;
@Service
public class PatientServiceImpl implements PatientService{
PatientDAO patientDAO;
@Autowired
public void setPatientDAO(PatientDAO patientDAO){
this.patientDAO = patientDAO;
}
@Transactional
@Override
public List<Patient> allPatients() {
return patientDAO.allPatients();
}
@Transactional
@Override
public void add(Patient patient) {
patientDAO.add(patient);
}
@Transactional
@Override
public void delete(Patient patient) {
patientDAO.delete(patient);
}
@Transactional
@Override
public void edit(Patient patient) {
patientDAO.edit(patient);
}
@Transactional
@Override
public Patient getByID(int id) {
return patientDAO.getByID(id);
}
}
Main class:
package testgroup.private_clinic.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootClass {
public static void main(String[] args){
SpringApplication.run(testgroup.private_clinic.service.SpringBootClass.class, args);
}
}
Solution
Spring Boot uses classpath component scanning meaning, your entry-point class which is SpringBootClass will scan for all beans within its class path unless you configure it not to.
Looking into your project structure, SpringBootClass is under the testgroup.private_clinic.service package thus Spring Boot will only scan this package for beans and it only found the PatientServiceImpl however, before it injects this to the application context, it will need to inject first its dependency PatientDAO which is not part of the testgroup.private_clinic.service package thus, explains your error.
You have two options to fix this:
Move your SpringBootClass to the base package testgroup.private_clinic - this will make Spring Boot scan on all you components under this package and its sub-packages (e.g., service, dao)
Use @ComponentScan on your SpringBootClass and define there the base package you want to scan for beans.
@ComponentScan(basePackages = "testgroup.private_clinic")
Thanks and cheers!
Answered By - junbetterway