I must say I am a newbie on Spring, so most probably this would be easy to must of you reading this.
My example is very simple. I have the classes Main
, Business
and Client
, in order to getClients
from Business
I created the interface ClientInterface
that contains a <List>Client
, Autowired
to the list in beans.xml
.
What I am trying to do is to print the Clients that the Business has, but its throwing me the following error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clients': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public java.util.List com.springcourse.practice.Client.listClients; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springcourse.practice.Client] found for dependency [collection of com.springcourse.practice.Client]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=arrayClients)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.springcourse.practice.Main.main(Main.java:9)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: public java.util.List com.springcourse.practice.Client.listClients; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springcourse.practice.Client] found for dependency [collection of com.springcourse.practice.Client]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=arrayClients)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
... 13 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springcourse.practice.Client] found for dependency [collection of com.springcourse.practice.Client]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=arrayClients)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:814)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
... 15 more
Here are the content of the code
beans.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.springcourse.practice"></context:component-scan>
<bean id="arrayClients" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="firstClient"/>
<ref bean="secondClient"/>
<ref bean="thirdClient"/>
</list>
</constructor-arg>
</bean>
<bean id="firstClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 1"/>
<property name="address" value="Somewhere 1"/>
</bean>
<bean id="secondClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 2"/>
<property name="address" value="Somewhere 2"/>
</bean>
<bean id="thirdClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 3"/>
<property name="address" value="Somewhere 3"/>
</bean>
</beans>
ClientInterface
package com.springcourse.practice;
import java.util.List;
public interface ClientInterface {
public List<Client> getClients();
}
Client
package com.springcourse.practice;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("clients")
public class Client implements ClientInterface {
public String name;
public String address;
@Autowired
@Qualifier("arrayClients")
public List<Client> listClients;
public List<Client> getClients(){
return listClients;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Business
package com.springcourse.practice;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component("business")
public class Business {
public String name = "Programmer City";
public String getName() {
return name;
}
public String getClients() {
@SuppressWarnings("resource")
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/beans.xml");
Client clients = (Client) context.getBean("clients");
StringBuilder sb = new StringBuilder("The business name is: " + this.getName() + "\n");
sb.append("The clients the business " + this.getName() + " has are: \n");
for(Client client: clients.getClients()) {
sb.append("Client: " + client.name + " located in " + client.address + "\n");
}
return sb.toString();
}
}
Main
package com.springcourse.practice;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/beans.xml");
Business business = (Business) context.getBean("business");
System.out.println(business.getClients());
context.close();
}
}
Can somebody please tell me what I am doing wrong? Here is a link of the project if someone wants to test it: https://www.dropbox.com/s/isqahsxmxw8uxc1/Cap2_PracticeBusinessLocations_2.zip?dl=0
It is very hard to understand the errors. Thank you very much to everyone!
Edit beans.xml after solving
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.springcourse.practice"></context:component-scan>
<bean id="arrayClients" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="firstClient"/>
<ref bean="secondClient"/>
<ref bean="thirdClient"/>
</list>
</constructor-arg>
</bean>
<bean id="firstClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 1"/>
<property name="address" value="Somewhere 1"/>
</bean>
<bean id="secondClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 2"/>
<property name="address" value="Somewhere 2"/>
</bean>
<bean id="thirdClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 3"/>
<property name="address" value="Somewhere 3"/>
</bean>
<bean id="arrayClientsTheSecond" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="TheSecondfirstClient"/>
<ref bean="TheSecondsecondClient"/>
<ref bean="TheSecondthirdClient"/>
</list>
</constructor-arg>
</bean>
<bean id="TheSecondfirstClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 4"/>
<property name="address" value="Somewhere 4"/>
</bean>
<bean id="TheSecondsecondClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 5"/>
<property name="address" value="Somewhere 5"/>
</bean>
<bean id="TheSecondthirdClient" class="com.springcourse.practice.Client">
<property name="name" value="Client Name 6"/>
<property name="address" value="Somewhere 6"/>
</bean>
</beans>
When I execute the response is:
The business name is: Programmer City
The clients the business Programmer City has are:
Client: Client Name 1 located in Somewhere 1
Client: Client Name 2 located in Somewhere 2
Client: Client Name 3 located in Somewhere 3
Client: Client Name 4 located in Somewhere 4
Client: Client Name 5 located in Somewhere 5
Client: Client Name 6 located in Somewhere 6
But again, the two list are named different and the list elements too.
While there are many Java and Spring conventions that you could apply to improve your code (private fields instead of public, initializing a new ApplicationContext inside a bean method, etc.), I'll focus on the main issue.
You can simply remove the @Qualifier annotation on the autowired list - Spring can identify the required beans based on your configuration by their type.
The code works after this change.