Spring Constructor @Autowired and @Qualifier fails

13,476

Solution 1

The answer (hours later) is to use:

AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx);

After the beans definitions have been read, but before the context has been refreshed for the first time. This gets me what I want (constructor autowiring) without having to touch either my XML, or my Class definitions. It will also scale nicely (in the future I can continue writing XML and Classes just as above, and won't need to change anything. The final bit of code which worked was:

GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("config.xml"));
AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx);
ctx.refresh();

Solution 2

Since you don't have an empty constructor, you must specify the constructor-args, for Spring constructor resolution to work...

For example

package examples;

public class ExampleBean {

    private int years;             //No. of years to the calculate the Ultimate Answer
    private String ultimateAnswer; //The Answer to Life, the Universe, and Everything

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

you can explicitly specify the args by defining the bean as follows

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg type="int"><value>7500000</value></constructor-arg>
  <constructor-arg type="java.lang.String"><value>42</value></constructor-arg>
</bean> 

----------------------------- UPDATE --------------------------------

If you want to avoid adding constructor-args manually.. you can try autowiring them using

<bean name="GreatBean" class="mypackage.MyCoolClass" autowire="constructor" />
Share:
13,476

Related videos on Youtube

Cory Kendall
Author by

Cory Kendall

I'm really just battling for the reputation :) And free shirts? SOreadytohelp

Updated on September 16, 2022

Comments

  • Cory Kendall
    Cory Kendall over 1 year

    Simplified code (I'm using Spring 3.1.4).

    Here's a class that I want autowired:

    public class MyCoolClass {
    
        @Autowired
        public MyCoolClass(
            @Qualifier("CoolBean1") SomeOtherClass1 foo1,
            @Qualifier("CoolBean2") SomeOtherClass1 foo2
        ) {
            this.foo1 = foo1;
            this.foo2 = foo2;
        }
    
        // ...
    }
    

    Here is my spring config xml:

    <bean name="CoolBean1" class="mypackage.SomeOtherClass1"/>
    <bean name="CoolBean2" class="mypackage.SomeOtherClass1"/>
    <bean name="GreatBean" class="mypackage.MyCoolClass"/>
    

    And here's how I'm trying to get the bean:

    GenericApplicationContext ctx = new GenericApplicationContext();
    XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
    xmlReader.loadBeanDefinitions(new ClassPathResource("config.xml"));
    ctx.refresh();
    

    At the point in the refresh call, I encounter this:

    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'GreatBean' defined in class path resource [config.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [mypackage.MyCoolClass]: No default constructor found; nested exception is java.lang.NoSuchMethodException: mypackage.MyCoolClass.<init>()
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:943)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
            at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
            at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
            at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:472)
            at mypackage.Runner.main(Runner.java:234)
    
    Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [mypackage.MyCoolClass: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.amazon.maxis.security.gbac.AsynchronousFolderAuthorizationManager.<init>()
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
            ... 11 more
    
    Caused by: java.lang.NoSuchMethodException: mypackage.MyCoolClass.<init>()
            at java.lang.Class.getConstructor0(Class.java:2800)
            at java.lang.Class.getDeclaredConstructor(Class.java:2043)
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
            ... 12 more
    

    Questions:

    • Why do I need a default construtor? I wouldn't want it to be called.
    • Do I need "@Component" for some reason on the class? I see others doing this
    • Why does this code work (as far as I can tell) through my junit tests? (How I'm running them shown below.

    Here's the snippet for running unit tests:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:config.xml"})
    public class MyJunitTest {
        //...
    }
    
  • Biju Kunjummen
    Biju Kunjummen almost 11 years
    Nice, you can also achieve this by adding <context:annotation-config/> to your configuration file.