Note: This is intended to be a canonical answer for a common problem.
I have a Spring @Service
class (MileageFeeCalculator
) that has an @Autowired
field (rateService
), but the field is null
when I try to use it. The logs show that both the MileageFeeCalculator
bean and the MileageRateService
bean are being created, but I get a NullPointerException
whenever I try to call the mileageCharge
method on my service bean. Why isn't Spring autowiring the field?
Controller class:
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator();
return calc.mileageCharge(miles);
}
}
Service class:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- should be autowired, is null
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- throws NPE
}
}
Service bean that should be autowired in MileageFeeCalculator
but it isn't:
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
When I try to GET /mileage/3
, I get this exception:
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...
This question is related to
java
spring
null
nullpointerexception
autowired
This is only valid in case of Unit test.
My Service class had an annotation of service and it was @autowired
another component class. When I tested the component class was coming null. Because for service class I was creating the object using new
If you are writing unit test make sure you are not creating object using new object()
. Use instead injectMock.
This fixed my issue. Here is a useful link
I think you have missed to instruct spring to scan classes with annotation.
You can use @ComponentScan("packageToScan")
on the configuration class of your spring application to instruct spring to scan.
@Service, @Component
etc annotations add meta description.
Spring only injects instances of those classes which are either created as bean or marked with annotation.
Classes marked with annotation need to be identified by spring before injecting, @ComponentScan
instruct spring look for the classes marked with annotation. When Spring finds @Autowired
it searches for the related bean, and injects the required instance.
Adding annotation only, does not fix or facilitate the dependency injection, Spring needs to know where to look for.
Actually, you should use either JVM managed Objects or Spring-managed Object to invoke methods. from your above code in your controller class, you are creating a new object to call your service class which has an auto-wired object.
MileageFeeCalculator calc = new MileageFeeCalculator();
so it won't work that way.
The solution makes this MileageFeeCalculator as an auto-wired object in the Controller itself.
Change your Controller class like below.
@Controller
public class MileageFeeController {
@Autowired
MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
It seems to be rare case but here is what happened to me:
We used @Inject
instead of @Autowired
which is javaee standard supported by Spring. Every places it worked fine and the beans injected correctly, instead of one place. The bean injection seems the same
@Inject
Calculator myCalculator
At last we found that the error was that we (actually, the Eclipse auto complete feature) imported com.opensymphony.xwork2.Inject
instead of javax.inject.Inject
!
So to summarize, make sure that your annotations (@Autowired
, @Inject
, @Service
,... ) have correct packages!
This is the culprit of giving NullPointerException MileageFeeCalculator calc = new MileageFeeCalculator();
We are using Spring - don't need to create object manually. Object creation will be taken care of by IoC container.
if you are using a private
method, it will be null
, try to change private
to public
in controller.
Not entirely related to the question, but if the field injection is null, the constructor based injection will still work fine.
private OrderingClient orderingClient;
private Sales2Client sales2Client;
private Settings2Client settings2Client;
@Autowired
public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
this.orderingClient = orderingClient;
this.sales2Client = sales2Client;
this.settings2Client = settings2Client;
}
I found a similar post @Autowired bean is null when referenced in the constructor of another bean .
The root cause of the error can be explained in the Spring reference doc (Autowired) , as follow:
Autowired Fields
Fields are injected right after construction of a bean, before any config methods are invoked.
But the real reason behind this statement in Spring doc is the Lifecycle of Bean in Spring. This is part of Spring's design philosophy.
This is Spring Bean Lifecycle Overview: Bean needs to be initialized first before it can be injected with properties such as field. This is how beans are designed, so this is the real reason.
I hope this answer is helpful to you!
One of the below will work :
The class where you are using @Autowired is not a Bean (You may have used new() somewhere I am sure).
Inside the SpringConfig class you have not mentioned the packages the Spring should look for @Component ( I am talking about @ComponentScan(basePackages"here") )
If above two don't work .... start putting System.out.println() and figure out where it is going wrong.
In simple words there are mainly two reasons for an @Autowired
field to be null
YOUR CLASS IS NOT A SPRING BEAN.
THE FIELD IS NOT A BEAN.
If you are not coding a web application, make sure your class in which @Autowiring is done is a spring bean. Typically, spring container won't be aware of the class which we might think of as a spring bean. We have to tell the Spring container about our spring classes.
This can be achieved by configuring in appln-contxt or the better way is to annotate class as @Component and please do not create the annotated class using new operator. Make sure you get it from Appln-context as below.
@Component
public class MyDemo {
@Autowired
private MyService myService;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("test");
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
System.out.println("ctx>>"+ctx);
Customer c1=null;
MyDemo myDemo=ctx.getBean(MyDemo.class);
System.out.println(myDemo);
myDemo.callService(ctx);
}
public void callService(ApplicationContext ctx) {
// TODO Auto-generated method stub
System.out.println("---callService---");
System.out.println(myService);
myService.callMydao();
}
}
I once encountered the same issue when I was not quite used to the life in the IoC world. The @Autowired
field of one of my beans is null at runtime.
The root cause is, instead of using the auto-created bean maintained by the Spring IoC container (whose @Autowired
field is indeed properly injected), I am new
ing my own instance of that bean type and using it. Of course this one's @Autowired
field is null because Spring has no chance to inject it.
UPDATE: Really smart people were quick to point on this answer, which explains the weirdness, described below
ORIGINAL ANSWER:
I don't know if it helps anyone, but I was stuck with the same problem even while doing things seemingly right. In my Main method, I have a code like this:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
and in a token.xml
file I've had a line
<context:component-scan base-package="package.path"/>
I noticed that the package.path does no longer exist, so I've just dropped the line for good.
And after that, NPE started coming in. In a pep-config.xml
I had just 2 beans:
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
and SomeAbac class has a property declared as
@Autowired private Settings settings;
for some unknown reason, settings is null in init(), when <context:component-scan/>
element is not present at all, but when it's present and has some bs as a basePackage, everything works well. This line now looks like this:
<context:component-scan base-package="some.shit"/>
and it works. May be someone can provide an explanation, but for me it's enough right now )
Also note that if, for whatever reason, you make a method in a @Service
as final
, the autowired beans you will access from it will always be null
.
What hasn't been mentioned here is described in this article in the paragraph "Order of execution".
After "learning" that I had to annotate a class with @Component or the derivatives @Service or @Repository (I guess there are more), to autowire other components inside them, it struck me that these other components still were null inside the constructor of the parent component.
Using @PostConstruct solves that:
@SpringBootApplication
public class Application {
@Autowired MyComponent comp;
}
and:
@Component
public class MyComponent {
@Autowired ComponentDAO dao;
public MyComponent() {
// dao is null here
}
@PostConstruct
public void init() {
// dao is initialized here
}
}
You can also fix this issue using @Service annotation on service class and passing the required bean classA as a parameter to the other beans classB constructor and annotate the constructor of classB with @Autowired. Sample snippet here :
@Service
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void useClassAObjectHere(){
classA.callMethodOnObjectA();
}
}
If this is happening in a test class, make sure you haven't forgotten to annotate the class.
For example, in Spring Boot:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
....
Spring Boot continues to evolve. It is no longer required to use @RunWith
if you use the correct version of JUnit.
For @SpringBootTest
to work stand alone, you need to use @Test
from JUnit5 instead of JUnit4.
//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5
@SpringBootTest
public class MyTests {
....
If you get this configuration wrong your tests will compile, but @Autowired
and @Value
fields (for example) will be null
. Since Spring Boot operates by magic, you may have few avenues for directly debugging this failure.
I'm new to Spring, but I discovered this working solution. Please tell me if it's a deprecable way.
I make Spring inject applicationContext
in this bean:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils {
public static ApplicationContext ctx;
/**
* Make Spring inject the application context
* and save it on a static variable,
* so that it can be accessed from any point in the application.
*/
@Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
You can put this code also in the main application class if you want.
Other classes can use it like this:
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
In this way any bean can be obtained by any object in the application (also intantiated with new
) and in a static way.
Your problem is new (object creation in java style)
MileageFeeCalculator calc = new MileageFeeCalculator();
With annotation @Service
, @Component
, @Configuration
beans are created in the
application context of Spring when server is started. But when we create objects
using new operator the object is not registered in application context which is already created. For Example Employee.java class i have used.
Check this out:
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String name = "tenant";
System.out.println("Bean factory post processor is initialized");
beanFactory.registerScope("employee", new Employee());
Assert.state(beanFactory instanceof BeanDefinitionRegistry,
"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (name.equals(definition.getScope())) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
}
}
}
}
In addition, don't inject to a static
member, it will be null
.
Another solution would be putting call:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
To MileageFeeCalculator constructor like this:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- will be autowired when constructor is called
public MileageFeeCalculator() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Source: Stackoverflow.com