Constructor injection and arrays with Spring
<p>I would like to understand whether there is a clean way to use constructor injection with arrays in spring-boot (1.3.5.RELEASE).</p>

<p>I've created this simple app that better explains my question:</p>

<pre><code>package com.stackoverflow;

import java.util.Arrays;
import java.util.stream.IntStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class Application {

    private static class Car { }

    @Bean
    public Car[] cars() {
        return IntStream.range(0, 10).mapToObj(i -&gt; new Car()).toArray(Car[]::new);
    }

    @Component
    private static class Road implements CommandLineRunner {

        private final Car[] cars;

        @Autowired
        public Road(Car[] cars) {
            this.cars = cars;
        }

//      @Resource
//      private Car[] cars;

        @Override
        public void run(String... args) throws Exception {
            System.out.println(Arrays.toString(cars));
        }

    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
</code></pre>

<p>I understand that @Autowired works by type, so the reason why the previous application does not work is because when the Car[] has to be injected, Spring first tries to find all Car beans but, since there is no Car bean, the following exception is thrown:</p>

<pre><code>org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'application.Road' defined in file [/spring-array-injection/target/classes/com/stackoverflow/Application$Road.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.stackoverflow.Application$Car[]]: No qualifying bean of type [com.stackoverflow.Application$Car] found for dependency [array of com.stackoverflow.Application$Car]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.stackoverflow.Application$Car] found for dependency [array of com.stackoverflow.Application$Car]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at com.stackoverflow.Application.main(Application.java:44) [classes/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.stackoverflow.Application$Car] found for dependency [array of com.stackoverflow.Application$Car]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]
    ... 19 common frames omitted
</code></pre>

<p>I also understand that if I replace the constructor injection with field injection + @Resource everything works because the array is injected by name instead of type.</p>

<p>So, am I missing something or is it a real spring limitation (i.e. it is currently not possible to use constructor injection with arrays/lists of object in spring)?</p>

<h3>UPDATE 1</h3>

<p>Wow, I thought this question had a shorter life but the case is not solved yet. I will post the two (ugly) workarounds I've tested so far:</p>

<ol>
<li><p>A wrapper around the array is injected instead of the plain array:</p>

<pre><code>package com.stackoverflow.workaround.arrayholder;

import java.util.Arrays;
import java.util.stream.IntStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class Application {

    private static class ArrayHolder&lt;T&gt; {

        private final T array;

        public ArrayHolder(T array) {
            this.array = array;
        }

        public T getArray() {
            return array;
        }

    }

    private static class Car { }

    @Bean
    public ArrayHolder&lt;Car[]&gt; cars() {
        return new ArrayHolder&lt;&gt;(IntStream.range(0, 10).mapToObj(i -&gt; new Car()).toArray(Car[]::new));
    }

    @Component
    private static class Road implements CommandLineRunner {

        private final Car[] cars;

        @Autowired
        public Road(ArrayHolder&lt;Car[]&gt; cars) {
            this.cars = cars.getArray();
        }

        @Override
        public void run(String... args) throws Exception {
            System.out.println(Arrays.toString(cars));
        }

    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
</code></pre></li>
<li><p>The beans are dynamically created and registered using the BeanFactoryPostProcessor:</p>

<pre><code>package com.stackoverflow.workaround.dynamicregistration;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class Application implements BeanFactoryPostProcessor {

    private static class Car { }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        AtomicInteger atomicInteger = new AtomicInteger();
        IntStream.range(0, 10)
            .mapToObj(i -&gt; new Car())
            .forEach(car -&gt; beanFactory.registerSingleton(String.valueOf(atomicInteger.getAndIncrement()), car));
    }

    @Component
    private static class Road implements CommandLineRunner {

        private final Car[] cars;

        @Autowired
        public Road(Car[] cars) {
            this.cars = cars;
        }

        @Override
        public void run(String... args) throws Exception {
            System.out.println(Arrays.toString(cars));
        }

    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
</code></pre></li>
</ol>

<h3>Update 2</h3>

<p>It turns out that constructor injection of arrays, collections and maps will be possible starting from Spring 4.3 (see <a href="https://jira.spring.io/browse/SPR-14332" rel="nofollow">issue</a>).</p>