Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor injection using Spring annotation @Autowired does not work

I have created 2 simple classes. Constructor of one class is annotated as @Autowired. It accepts the object of another class. But this code fails.

Classes :- 1) SimpleBean.java

@Configuration
public class SimpleBean {
  InnerBean prop1;

  public InnerBean getProp1() {
    return prop1;
  }

  public void setProp1( InnerBean prop1) {
    System.out.println("inside setProp1 input inner's property is "
        + prop1.getSimpleProp1());
    this.prop1 = prop1;
  }

  @Autowired(required=true)
  public SimpleBean(InnerBean prop1) {
    super();
    System.out.println("inside SimpleBean constructor inner's property is "
        + prop1.getSimpleProp1());
    this.prop1 = prop1;
  }
}

2) Inner.java

@Configuration
public class InnerBean {
  String simpleProp1;

  public String getSimpleProp1() {
    return simpleProp1;
  }

  public void setSimpleProp1(String simpleProp1) {
    this.simpleProp1 = simpleProp1;
  }

}

When I try to load ApplicationConext

ApplicationContext acnxt = new AnnotationConfigApplicationContext("com.domain");

It gives following error :-

Exception in thread "main" org.springframework.beans.factory.BeanCreationException:         Error creating bean with name 'simpleBean' defined in file [C:\Users\owner\Documents\Java Project\MyWorkSpace\springMVCSecond\WebContent\WEB-INF\classes\com\domain\SimpleBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.domain.SimpleBean$$EnhancerByCGLIB$$4bc418be]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.domain.SimpleBean$$EnhancerByCGLIB$$4bc418be.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:965)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911)
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:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:75)
at com.test.SpringAnnotationTest.main(SpringAnnotationTest.java:12)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.domain.SimpleBean$$EnhancerByCGLIB$$4bc418be]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.domain.SimpleBean$$EnhancerByCGLIB$$4bc418be.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:958)
... 12 more
Caused by: java.lang.NoSuchMethodException: com.domain.SimpleBean$$EnhancerByCGLIB$$4bc418be.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getDeclaredConstructor(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:65)
... 13 more

If I introduce no-arg constructor in SimpleBean class. It does not give error. But this does not give me pre-poulated object of SimpleBean ( as in XML configuration using < constructor-arg > ). So when using annotation, is it mandatory to have no-arg constructor ? What is the appropriate way out ?

like image 383
Kaushik Lele Avatar asked Apr 20 '12 07:04

Kaushik Lele


2 Answers

From the javadoc of @Configuration:

 Configuration is meta-annotated as a {@link Component}, therefore Configuration
 classes are candidates for component-scanning and may also take advantage of
 {@link Autowired} at the field and method but not at the constructor level.

So you'll have to find some other way to do it, unfortunately.

like image 138
artbristol Avatar answered Oct 15 '22 02:10

artbristol


I believe you are mixing up the @Configuration and @Component annotation. As per the spring docs, @Configuration is used to create beans using Java code (any methods annotated with @Bean create a bean, whereas classes annotated with @Component are automatically created..

I hope the following illustrates this:

InnerBean.java:

// this bean will be created by Config
public class InnerBean {
  String simpleProp1;

  public String getSimpleProp1() {
    return simpleProp1;
  }

  public void setSimpleProp1(String simpleProp1) {
    this.simpleProp1 = simpleProp1;
  }
}

SimpleBean.java:

// This bean will be created because of the @Component annotation, 
// using the constructor with the inner bean autowired in
@Component
public class SimpleBean {
  InnerBean prop1;

  public InnerBean getProp1() {
    return prop1;
  }

  @Autowired(required = true)
  public SimpleBean(InnerBean prop1) {
    this.prop1 = prop1;
  }
}

OuterBean.java

// this bean will be created by Config and have the SimpleBean autowired.
public class OuterBean {
  SimpleBean simpleBean;

  @Autowired
  public void setSimpleBean(SimpleBean simpleBean) {
    this.simpleBean = simpleBean;
  }

  public SimpleBean getSimpleBean() {
    return simpleBean;
  }
}

Config.java

// this class will create other beans
@Configuration
public class Config {
  @Bean
  public OuterBean outerBean() {
    return new OuterBean();
  }

  @Bean
  public InnerBean innerBean() {
    InnerBean innerBean = new InnerBean();
    innerBean.setSimpleProp1("test123");
    return innerBean;
  }
}

Main.java:

public class Main {
  public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext("com.acme");
    OuterBean outerBean = ctx.getBean("outerBean", OuterBean.class);
    System.out.println(outerBean.getSimpleBean().getProp1().getSimpleProp1());
  }
}

The main class uses the AnnotationConfigApplicationContext to scan for both @Configuration and @Component annotations and create the beans accordingly.

like image 21
beny23 Avatar answered Oct 15 '22 02:10

beny23