BeanInstantiationException: Failed to instantiate : No default constructor found;

Viewed 2316

I am experimenting with Spring 5, when I run the Test Application, it throws this exception. I understand that we need a zero-argument constructor if we are using @Autowired for Fields and Setter Methods since the bean is first instantiated with a zero-argument constructor and then dependant beans are injected. But why do we need a zero-argument constructor if the constructor is @Autowired since this constructor would be used for instantiating the bean?

is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.spring.hello.Student]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.spring.hello.Student.<init>()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1155)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)

Student.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Student {
    
    private PersonalInfo pI;
    
    @Autowired
    public Student (PersonalInfo pI) {
        this.pI = pI;
    }
    
}

PersonalInfo.java

@Component
public class PersonalInfo {
    
    String name;
    
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private PersonalInfo() {
        System.out.println("constructor...");
    }
    
    public String printHello() {
        return "PersonalInfo...";
    }
}

Test.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.hello.Student;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext("/com/spring/resources/applicationContext.xml");
        Student bean = (Student) context.getBean("student");
        System.out.println(bean);
        
        
    }

}

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <context:annotation-config/>
    <bean id="student" class="com.spring.hello.Student">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
    <bean id="personalInfo" class="com.spring.hello.personalInfo">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
</beans>

EDIT

After updating the Test class, I am getting

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'student' available.
1 Answers

Your issue is that you are mixing annotation configuration with XML configuration. Because you create an instance of ClassPathXmlApplicationContext, only what is in the XML will be taken as configuration and your @Autowired annotation gets ignored.

To fix the error with xml you need to add the bean injection in the xml definition:

    <bean id="student" class="com.spring.hello.Student">
        <constructor-arg ref="personalInfo" />
    </bean>
    <bean id="personalInfo" class="com.spring.hello.personalInfo"></bean>

If you want to use annotation config instead, you can create an instance of AnnotationConfigApplicationContext instead. You then still need to annotate student and personalInfo with @Component so Spring can find them as beans when scanning the provided package.

@Component
public class PersonalInfo {
  ...
}

@Component
public class Student{
   ...
}
public static void main(String[] args) {
    var ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.spring.hello");
    ctx.refresh();
}
Related