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)
...
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:
and in a
token.xml
file I've had a lineI 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:and SomeAbac class has a property declared as
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:and it works. May be someone can provide an explanation, but for me it's enough right now )
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:You can put this code also in the main application class if you want.
Other classes can use it like this:
In this way any bean can be obtained by any object in the application (also intantiated with
new
) and in a static way.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.
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.
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.
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.