This is a continuation to one of my SO questions.
I extended the same example and I expected it to work, however I am getting NullPointerException.
Here is the complete source code:
FirstBean.java
package com.example;
import org.springframework.stereotype.Component;
@Component
public class FirstBean {
public FirstBean() {
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "FirstBean [name=" + name + "]";
}
}
SomeBean.java
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Component
@Configuration
@ComponentScan(basePackages = { "com.example" })
public class SomeBean {
@Autowired
private FirstBean fb;
@Bean
FirstBean instantiateFirstBean() {
return new FirstBean();
}
public SomeBean() {
// this.fb.setName("Some Name"); -> this was causing problem as
// bean isn't still created fully
}
public void print() {
this.fb.toString();
}
@PostConstruct
void post() {
fb.setName("Some name");
}
}
MainDriver.java
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
@Configuration
@ComponentScan(basePackages = { "com.example" })
@PropertySource(ignoreResourceNotFound = true, value = "classpath:/application.props")
public class MainDriver {
@Autowired
private Environment env;
@Autowired
private ConfigurableEnvironment cenv;
@Autowired
ApplicationContext ctx;
@Autowired
private SomeBean sb;
@Bean
public SomeBean instantiateSomeBean() {
return new SomeBean();
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainDriver.class);
MainDriver l = ctx.getBean(MainDriver.class);
System.out.println("In main() the ctx is " + ctx);
l.test();
}
public void test() {
System.out.println("hello");
sb.print();
}
}
I was expecting SomeBean
to get Autowired
(ctx
, env
, cenv
are getting Autowired perfectly), but it is not getting and I am getting run time exception.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainDriver': Unsatisfied dependency expressed through field 'sb'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainDriver': Unsatisfied dependency expressed through field 'sb'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
at com.example.MainDriver.main(MainDriver.java:37)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1228)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581)
... 14 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:182)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1220)
... 25 more
Caused by: java.lang.NullPointerException
at com.example.SomeBean.<init>(SomeBean.java:23)
at com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b.<init>(<generated>)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:170)
... 27 more
I am mentioning @Bean
as well which I hoped it will tell how to create those beans, but still getting the exception.
What am I not understanding, and how can I fix it?
I think this is because Spring will first have to instantiate your SomeBean
class and then it will try to autowire FirstBean
through reflection because you put @Autowired
annotation on the field.
You are trying to access FirstBean
dependency in SomeBean
constructor but when constructor of SomeBean
is invoked, when context is being created, the FirstBean
dependency is null because Spring has not autowired the dependency yet - it will try to autowire it through reflection after object creation. That is why you are getting NullPointerException
there. The same situation happens with your SomeBean
class - decide on one approach.
Additionaly it is strange that you create classes that are both annotated with @Configuration
and @Component
. Please refere to this SO question to see potential errors.
Moreover there are some issues in your configuration. You annotate FirstBean
with @Component
annotation and you still create a @Bean
annotated method that returns instance of this class. You should decide on one apprach - you instantiate it for application context using @Bean
annotation or you annotate this class with @Component
and you let component scan automatically create it for you.
EDIT :
You should decide if you want to use @ComponentScan
or you want to create your beans for context through @Bean
annotation - right now you are mixing different types and you will get errors for duplicate bean definitions when trying to autowire by type, because in your current implementation there will be 2 bean for SomeBean
and 2 beans for FirstBean
in your context - they will only have different ids. Note that error that I pointed out with NPE expection has nothing to do with it. I will propose a solution using automated package scanning :
FirstBean class
@Component
public class FirstBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "FirstBean [name=" + name + "]";
}
}
SomeBean class
@Component
public class SomeBean {
private FirstBean fb;
@Autowired
public SomeBean(FirstBean firstBean) {
this.fb = firstBean;
this.fb.setName("Some Name");
}
public void print() {
this.fb.toString();
}
}
MyConfig class
@Configuration
@ComponentScan(basePackages = { "com.example" })
public class MyConfig {
}
MainDriver class
@Component
public class MainDriver {
@Autowired
private Environment env;
@Autowired
protected ConfigurableEnvironment cenv;
@Autowired
ApplicationContext ctx;
@Autowired
private SomeBean sb;
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
MainDriver l = ctx.getBean(MainDriver.class);
System.out.println("In main() the ctx is " + ctx);
l.test();
}
public void test() {
System.out.println("hello");
sb.print();
}
}