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)
...
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:
and:
In simple words there are mainly two reasons for an
@Autowired
field to benull
YOUR CLASS IS NOT A SPRING BEAN.
THE FIELD IS NOT A BEAN.
Also note that if, for whatever reason, you make a method in a
@Service
asfinal
, the autowired beans you will access from it will always benull
.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 sameAt last we found that the error was that we (actually, the Eclipse auto complete feature) imported
com.opensymphony.xwork2.Inject
instead ofjavax.inject.Inject
!So to summarize, make sure that your annotations (
@Autowired
,@Inject
,@Service
,... ) have correct packages!Another solution would be putting call:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
To MileageFeeCalculator constructor like this:
If this is happening in a test class, make sure you haven't forgotten to annotate the class.
For example, in Spring Boot: