Autowire reference beans into list by type

JavaSpring

Java Problem Overview


I have one class that has a list of objects of Daemon type.

class Xyz {    
    List<Daemon> daemons;
}

My spring configuration looks like this.

<bean id="xyz" class="package1.Xyz">
   <property name="daemons" ref="daemonsList">
</bean>
    
<bean id="daemon1" class="package1.DaemonImpl1"/>
<bean id="daemon2" class="package1.DaemonImpl2"/>

<bean id="daemonsList" class="java.util.ArrayList">
		<constructor-arg>
			<list>
				<ref bean="daemon1" />		
				<ref bean="daemon2" />
			</list>
		</constructor-arg>
</bean>

Now instead of explicitly wiring each daemon implementation in list, is it possible to autowire all beans of type Daemon automatically in list. Problem I am trying to solve is, If someone creates a bean of new implementation of Daemon class and forgets to wire it into list.

I have seen this question somewhere on stackoverflow but not able to find that again. Apologies for it.

Java Solutions


Solution 1 - Java

It should work like this (remove the ArrayList bean from your XML):

public Class Xyz {    

    private List<Daemon> daemons;

    @Autowired
    public void setDaemons(List<Daemon> daemons){
        this.daemons = daemons;
    }

}

I don't think there's a way to do this in XML.


See: 3.9.2. @Autowired and @Inject:

> It is also possible to provide all beans of a particular type from the > ApplicationContext by adding the annotation to a field or method that > expects an array of that type:

public class MovieRecommender {

  @Autowired
  private MovieCatalog[] movieCatalogs;

  // ...
}

> The same applies for typed collections:

public class MovieRecommender {

  private Set<MovieCatalog> movieCatalogs;

  @Autowired
  // or if you don't want a setter, annotate the field
  public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
      this.movieCatalogs = movieCatalogs;
  }

  // ...
}

BTW, as of Spring 4.x, these lists can be ordered automatically using the @Ordered mechanism.

Solution 2 - Java

Well, this can be achieved in two ways as stated in Spring Documentation.

Below is the excerpt from the documentation.

> With byType or constructor autowiring mode, you can wire arrays and typed collections.

1. autowire="byType"

Autowiring using "byType" can be achieved if the type of the bean defined in the xml matches the type of list.

Example:

Motor.java

package com.chiranth;
public interface Motor 
{
   public void start();
}

ElectricMotor1.java

package com.chiranth;
public class ElectricMotor1 implements Motor
{
     public void start() 
     { 
         System.out.println("Motor 1 Started.");
     }
}

ElectricMotor2.java

package com.chiranth;
public class ElectricMotor2 implements Motor
{
    public void start() 
    {
        System.out.println("Motor 2 Started.");
    }
}

TeslaModelX.java

package com.chiranth;
import java.util.List;
public class TeslaModelX 
{
	private List<Motor> motor;

	public List<Motor> getMotor()
	{
		return motor;
	}

	public void setMotor(List<Motor> motor) 
	{
		this.motor = motor;
	}

	public void goForward()
	{
		for(Motor m :motor)
			m.start();
		System.out.println("Going Forward.");
	}
}

Spring.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:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">
   
	<bean id="electricMotor1" class="com.chiranth.ElectricMotor1"/>
	<bean id="electricMotor2" class="com.chiranth.ElectricMotor2"/>
	
	<bean id="modelX" class="com.chiranth.TeslaModelX" autowire="byType"/>
</beans>

Test.java

package com.chiranth;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test 
{
	public static void main(String[] args) 
	{
		ApplicationContext context= new ClassPathXmlApplicationContext("Spring.xml");
		TeslaModelX modelx=(TeslaModelX)context.getBean("modelX");
		modelx.goForward();
	}
}

OUTPUT:

Motor 1 Started.
Motor 2 Started.
Going Forward.

2. autowire="constructor"

Autowiring using "constructor" can be achieved if the type of the bean defined in the xml matches the type of the argument in the constructor.

Example:

Considering the above Motor.java , ElectricMotor1.java and ElectricMotor2.java.

TeslaModelX.java

package com.chiranth;
import java.util.List;
public class TeslaModelX 
{
	private List<Motor> motor;

	public TeslaModelX(List<Motor> motor)
	{
		this.motor=motor;
	}
	
	public void goForward()
	{
		for(Motor m:motor)
			m.start();
		System.out.println("Going Forward.");
	}
}

Spring.xml

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">
   
	<bean id="electricMotor1" class="com.chiranth.ElectricMotor1"/>
	<bean id="electricMotor2" class="com.chiranth.ElectricMotor2"/>
	
	<bean id="modelX" class="com.chiranth.TeslaModelX" autowire="constructor"/>
</beans>

Test.java

package com.chiranth;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test 
{
	public static void main(String[] args) 
	{
		ApplicationContext context= new ClassPathXmlApplicationContext("Spring.xml");
		TeslaModelX modelX=(TeslaModelX)context.getBean("modelX");
		modelX.goForward();
	}
}

OUTPUT:

Motor 1 Started.
Motor 2 Started.
Going Forward.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRandomQuestionView Question on Stackoverflow
Solution 1 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 2 - JavachiranthView Answer on Stackoverflow