positron
positron

Reputation: 3693

Injecting two beans of the same type

As an exercise I have the following setup

<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.xsd"
    xmlns:p="http://www.springframework.org/schema/p">


    <bean id="employee" class="com.example.demo.model.Employee" p:name="bob">
        <constructor-arg name="id" value="1"/>
    </bean>

    <bean id="employee2" class="com.example.demo.model.Employee" p:name="Mike" p:id="2" />

    <bean id="department" class="com.example.demo.model.Department">
        <constructor-arg ref="employee" />
        <property name="empl2" ref="employee2" />
    </bean>
</beans>

Employee class

@Scope("prototype")
public class Employee {

    private long id;
    private String name;
    private Department department;

    //@ConstructorProperties({"id", "namez"}) 
    // matches constructor names with those in XML without altering
    // constructor names
    public Employee(int id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Employee() {
        // TODO Auto-generated constructor stub
    }

    public Employee(int id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + "]";
    }

}

Department class

public class Department {
    @Qualifier("employee")
    private Employee empl;
    @Qualifier("employee2")
    private Employee empl2;

    public Department(Employee empl) {
        this.empl = empl;
    }

    @Override
    public String toString() {
        return String.format("Employee: %s, Employee 2: %s", empl, empl2);
    }

    public void setEmpl2(Employee empl2) {
        this.empl2 = empl2;
    }

    public Employee getEmpl2() {
        return empl2;
    }

}

When I run application I get error

No qualifying bean of type 'com.example.demo.model.Employee' available: expected single matching bean but found 2: employee,employee2

I thought using Qualifier would fix this, but it does not. What am I doing wrong?

Also in logs I get debug message

11:17:58.655 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'employee'
11:17:58.693 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'employee2'
11:17:58.693 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'department'

Which means employee instances are singleton, but I thought by defining Scope("prototype") I would get new instances of Employee each time?

PS Exception:

12:01:16.982 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@18ef96
12:01:17.084 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [employee.xml]
12:01:17.106 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'department'
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.model.Employee' available: expected single matching bean but found 2: employee,employee2
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1144)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:411)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:344)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:337)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1123)
    at com.example.demo.DemoApplication.main(DemoApplication.java:17)

Upvotes: 0

Views: 79

Answers (2)

Antoniossss
Antoniossss

Reputation: 32535

Its because you are mixing java based config with XML config. Move to Java based config and you will not have similar issues in future.

For now, you must define your bean as prototype in XML

<bean id="employee2" class="com.example.demo.model.Employee" scope="prototype"/>

Well you obviously hiddent the most important part of the code -because its straightforward and irrelevant - which is:

ApplicationContext ctx = new ClassPathXmlApplicationContext("employee.xml"); 
Employee employee = ctx.getBean(Employee.class); // what do we got here?
System.out.println(employee); 
Department bean = ctx.getBean(Department.class); 
System.out.println(bean); 

I see no used name here, so both emplyees matches.

Upvotes: 1

Farshad Falaki
Farshad Falaki

Reputation: 74

Add @Autowired be qualifier annotation

Upvotes: 0

Related Questions