Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 365 Vote(s) - 3.48 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why is my Spring @Autowired field null?

#1
*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)
...
Reply

#2
*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**.
Reply

#3
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();

}

}
Reply

#4
The field annotated `@Autowired` is `null` because Spring doesn't know about the copy of `MileageFeeCalculator` that you created with `new` and didn't know to autowire it.

[The Spring Inversion of Control (IoC) container](

[To see links please register here]

) has three main logical components: a registry (called the `ApplicationContext`) of components (beans) that are available to be used by the application, a configurer system that injects objects' dependencies into them by matching up the dependencies with beans in the context, and a dependency solver that can look at a configuration of many different beans and determine how to instantiate and configure them in the necessary order.

The IoC container isn't magic, and it has no way of knowing about Java objects unless you somehow inform it of them. When you call `new`, the JVM instantiates a copy of the new object and hands it straight to you--it never goes through the configuration process. There are three ways that you can get your beans configured.

I have posted all of this code, using Spring Boot to launch, at [this GitHub project](

[To see links please register here]

); you can look at a full running project for each approach to see everything you need to make it work. **Tag with the `NullPointerException`: [`nonworking`](

[To see links please register here]

)**

## Inject your beans ##

The most preferable option is to let Spring autowire all of your beans; this requires the least amount of code and is the most maintainable. To make the autowiring work like you wanted, also autowire the `MileageFeeCalculator` like this:

@Controller
public class MileageFeeController {

@Autowired
private MileageFeeCalculator calc;

@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}

If you need to create a new instance of your service object for different requests, you can still use injection by using [the Spring bean scopes](

[To see links please register here]

).

**Tag that works by injecting the `@MileageFeeCalculator` service object: [`working-inject-bean`](

[To see links please register here]

)**

## Use @Configurable ##

If you really need objects created with `new` to be autowired, you can [use the Spring `@Configurable` annotation along with AspectJ compile-time weaving](

[To see links please register here]

) to inject your objects. This approach inserts code into your object's constructor that alerts Spring that it's being created so that Spring can configure the new instance. This requires a bit of configuration in your build (such as compiling with `ajc`) and turning on Spring's runtime configuration handlers (`@EnableSpringConfigured` with the JavaConfig syntax). This approach is used by the Roo Active Record system to allow `new` instances of your entities to get the necessary persistence information injected.

@Service
@Configurable
public class MileageFeeCalculator {

@Autowired
private MileageRateService rateService;

public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}

**Tag that works by using `@Configurable` on the service object: [`working-configurable`](

[To see links please register here]

)**

## Manual bean lookup: not recommended ##

This approach is suitable only for interfacing with legacy code in special situations. It is nearly always preferable to create a singleton adapter class that Spring can autowire and the legacy code can call, but it is possible to directly ask the Spring application context for a bean.

To do this, you need a class to which Spring can give a reference to the `ApplicationContext` object:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

public static ApplicationContext getContext() {
return context;
}
}

Then your legacy code can call `getContext()` and retrieve the beans it needs:

@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}

**Tag that works by manually looking up the service object in the Spring context: [`working-manual-lookup`](

[To see links please register here]

)**
Reply

#5
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();
}
}
Reply

#6
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.
<br>

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.
Reply

#7
**UPDATE:** Really smart people were quick to point on [this][1] 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 )


[1]:

[To see links please register here]

Reply

#8
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!
Reply

#9
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);
}
}

Reply

#10
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`.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through