@Autowired bean is null when referenced in the constructor of another bean
Autowiring (link from Dunes comment) happens after the construction of an object. Therefore they will not be set until after the constructor has completed.
If you need to run some initialization code, you should be able to pull the code in the constructor into a method, and annotate that method with @PostConstruct
.
@Autowired object is null
counter
is a member variable of MessageBoxController. Spring use reflection to construct MessageBoxController instance. It would be initialized before dependency injection of dao. More details can be found here: https://stackoverflow.com/a/49443630/6644123
We can try to rewrite counter's initialization time.
An example may be like code below:
@RestController
public class MessageBoxController {
@Autowired
MessageBoxDAO dao;
private final AtomicLong counter = new AtomicLong(0);
@PostConstruct
public void initialize() {
// initialize counter after dependency injection of dao
counter.set(dao.getLatestID());
}
...
}
Why call to @Autowired field inside my bean returns null?
Because you are accessing the driver.wait
field using a field reference. Spring auto-wire is based on generated proxies which are applied to methods, especially when some of the beans are @Lazy
. As per docs:
In addition to its role for component initialization, you can also place the
@Lazy
annotation on injection points marked with@Autowired
or@Inject
. In this context, it leads to the injection of a lazy-resolution proxy.
Below should work assuming that there is a corresponding getWait()
method:
driver.getWait().doStuff()
Autowired throws null pointer
You could use constructor injection instead of field injection if you want the value to be extracted in the constructor itself like :
public class ClassB {
public ClassA classA;
@Autowired
public ClassB(ClassA classA){
this.classA = classA;
System.out.println(classA.str);
}
}
As of Spring 4.3, classes with a single constructor can omit the @Autowired
annotation.Spring will encounter our 'ClassB' class while doing a package scan and will initialize its instance by calling the @Autowired
annotated constructor.
In your code , the autowiring happens after the no args constructor is invoked.So when you try to access the 'str' using classA object it causes null pointer exception as classA is yet to be autowired.
Why is my Spring @Autowired field null?
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 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; 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
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.
Tag that works by injecting the @MileageFeeCalculator
service object: working-inject-bean
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 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
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
Null pointer exception for autowired class method
The problem is in your C
class.
@Component
class C{
@Autowired
A config;
String username = config.gtUsername();
}
The sequence during Spring's initialization was like this:
- Create an instance of
C
(by callingnew C()
)
This constructor callsusername = config.gtUsername()
and fails with aNullPointerException
becauseconfig
is stillnull
. - Process the
@Autowired
(initialize yourconfig
property)
But of course it doesn't get this far because the exception already happened in step 1.
You can fix this problem by removing the initialization of your username
property from the constructor and instead put it into a separate method
(let's call it init()
) and annotate it with @PostConstruct
.
See also Spring PostConstruct and PreDestroy Annotations.
@Component
class C{
@Autowired
A config;
String username;
@PostConstruct
void init() {
username = config.getUsername();
}
}
Then the sequence during Spring's initialition will be like this:
- Create a
C
instance
(by callingnew C()
) - Process the
@Autowired
.
(This initializes yourconfig
property) - Call the
@PostConstruct
-annotated method.
(This initializes yourusername
property using the already initializedconfig
property)
Another even simpler way to fix your problem, is to use constructor
injection (as @Ferry already suggested in his comment):
Instead of relying on the implicit default constructor,
you provide an @Autowired
-annotated constructor which
can take an A config
parameter.
Furthermore: By doing so, you will not need theA config
property anymore.
@Component
class C{
String username;
@Autowired
C(A config) {
username = config.getUsername();
}
}
Then the sequence during Spring's initialization will be like this:
- Process the
@Autowired
(create an instance ofC
by callingnew C(config)
whereconfig
is anA
instance previously created during the autowiring process)
This initializes yourusername
property using theconfig
received by the constructor.
Spring bean is created, but is null when Autowired
As @Mick pointed out, field injection necessarily takes place after the constructor is finished (there's no other way for Spring to see the instance and manipulate it). Modify your class to use constructor injection, and you'll both make your dependencies more explicit (and thus easier to test, for example) and eliminate what's essentially a race condition:
public class Bar {
private Foo foo;
@Autowired
public Bar(Foo foo) {
this.foo = foo;
foo.func();
}
}
Related Topics
What Are Classes, References, and Objects
When Is the @JSONproperty Property Used and What Is It Used For
How to Compare Two Dates Without the Time Portion
Inject an Ejb into Jax-Rs (Restful Service)
Why Is the Clone() Method Protected in Java.Lang.Object
Any Way to Invoke a Private Method
Differencebetween Method Overloading and Overriding
Can Java 8 Code Be Compiled to Run on Java 7 Jvm
How to Obtain Method Parameter Name Using Java Reflection
String Concatenation in Java - When to Use +, Stringbuilder and Concat
How Is an Overloaded Method Chosen When a Parameter Is the Literal Null Value
How Does Auto Boxing/Unboxing Work in Java
Cannot Parse String in Iso 8601 Format, Lacking Colon in Offset, to Java 8 Date
What Does the Question Mark in Java Generics' Type Parameter Mean