I was trying to follow a tutorial over at Mkyong regarding Spring. I created two simple classes, Customer and Person, which look like so:
Customer:
public class Customer {
private Person person;
public Customer() {
}
//Getters and setters for person here
public String toString() {
return "Customer [person=" + person +"]";
}
}
Person:
public class Person {
private String name;
private String address;
private int age;
public Person() {
}
public Person(String name, String address, int age) {
this.name = name;
this.address = address;
this.age = age;
}
//All getters and setters
public String toString() {
return "Person [address=" + address + ", age=" + age + ", name=" + name + "]";
}
}
I then created a Bean configuration file, using an inner bean (which is why I was taking the tutorial) that looks like so:
// Standard bean declarations
<bean id="CustomerBean" class="com.andrew.SpringInnerBeans.Customer">
<property name="person">
<bean class="com.andrew.SpringInnerBeans.Person">
<property name="name" value="Andrew" />
<property name="address" value="Address" />
<property name="age" value="27" />
</bean>
</property>
</bean>
</beans>
Finally, I created a MainApp to run this code:
public static void main (String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
"NewBean.xml"});
Customer cust = (Customer) context.getBean("CustomerBean");
System.out.println(cust);
}
Now, to my understanding, this is what is happening:
The xml file is loaded and the bean with id CustomerBean is stored in the reference cust (which is a Customer object). CustomerBean takes an argument, "person", and the details of the three parameters which create the Person are supplied as the inner bean of customerBean.
In the MainApp, the toString method of the reference cust is called and the proper output is displayed.
As I am specifically providing references in my examples, why is a no argument constructor required to run this code? If I remove either the empty Customer or empty Person constructors, the code fails. Why does it fail, at run-time, when the bean I've set up doesn't require a no argument constructor?
Edit:
Example of code pass:
Customer [person=Person [address=4 Ascot House, age=27, name=Andrew]]
Example of code fail:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean' defined in class path resource [NewBean.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.andrew.SpringInnerBeans.MainApp.main(MainApp.java:10)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1088)
... 13 more
Caused by: java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getDeclaredConstructor(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
... 14 more
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean' defined in class path resource [NewBean.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.andrew.SpringInnerBeans.MainApp.main(MainApp.java:10)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1088)
... 13 more
Caused by: java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getDeclaredConstructor(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
... 14 more
Well look again at what you are asking from the Spring container point of view.
Customer
, with only properties : ok create it as new Customer()
using the no-arg constructor and keep it for the moment.Person
with only properties : ok create it as new Person()
, still using the no-arg constructor, give it an arbitrary name and keep it for the momentPerson
bean with its properties using the setters : ok it is readyCustomer
bean with its only property using the setter and the Person
bean as parameter : ok it is readySo you get the beans from the application context and have no new
in your own code, but Spring has constructed them for you, and did use the no-arg constructors.
You could instead have for example :
public class Customer {
private Person person;
public Customer(Person person) {
this.person = person;
}
...
}
and your XML would have to be :
<bean id="CustomerBean" class="com.andrew.SpringInnerBeans.Customer">
<constructor-arg>
<bean class="com.andrew.SpringInnerBeans.Person">
<property name="name" value="Andrew" />
<property name="address" value="Address" />
<property name="age" value="27" />
</bean>
</constructor-arg>
</bean>
That way, Spring would have first constructed Person
bean as above and would have created Customer
bean as new Customer(person)
using the one arg constructor.
because it uses fields injection instead your Person(String name, String address, int age) constructor. Please try something like:
...
<property name="person">
<bean class="com.andrew.SpringInnerBeans.Person">
<constructor-arg index="0" value="Andrew"/>
<constructor-arg index="1" value="Address"/>
<constructor-arg index="2" value="27"/>
</bean>
</property>
...
instead. Thats solution for Person class, for Customer - I dunno ; )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With