0

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.

andres.gtz
  • 624
  • 12
  • 22

1 Answers1

1

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.

unlimitednzt
  • 1,035
  • 2
  • 16
  • 25
  • Removing Qualifier did it, and Business class has @Component("business") already. But, if I had two beans is when I needed to specify Qualifier? Thank you – andres.gtz Apr 30 '18 at 22:24
  • You're welcome, you could mark the answer as accepted if you're satisfied. @Qualifier is indeed used when autowiring a bean, and there are multiple candidates involved. However, your qualifier is for a List type, not the Client beans - and Spring can tell by your configuration that you want to simply add all Client bean to the list. It's not typically used with xml configuration, but with Java configuration. You can read more at https://stackoverflow.com/questions/40830548/spring-autowired-and-qualifier?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – unlimitednzt Apr 30 '18 at 22:29
  • Maybe edit your post with the code so I can see exactly what you did – unlimitednzt Apr 30 '18 at 22:30
  • AFAIK, Spring 4 will, behind the curtains, when you autowire a list of a given type, add all of the beans that are of that type. In other words, both lists in your beans.xml file are ignored and not even used. You can even remove them from the xml and see that they will still work. See https://www.intertech.com/Blog/spring-4-ordering-autowired-collections/ – unlimitednzt Apr 30 '18 at 22:48
  • You are right, I did and it certainly executed them. So, I will need to use Qualifier when I add another bean with different type, and only then it will not crush. Correct? – andres.gtz Apr 30 '18 at 22:52
  • 1
    No. Just forget about using Qualifier with Spring 4 and lists defined in XML. Qualifier is for a situation where you have different beans of the *same* type and you need to specify one of them while autowiring, not for beans of different types. I suggest you read the documentation. – unlimitednzt Apr 30 '18 at 22:54
  • Got it. Thank you. – andres.gtz Apr 30 '18 at 23:10