1. Introduction

In this post, we would learn how to solve thee NullPointerException when using @Autowired in spring applications.

2. Environment

  • All Spring Applications
  • java 1.8+

3. The code

3.1 The class diagram

Say we have three classes: classes_20190701

They are:

  • MyController: This is a @Controller class which accept http requests, it depends on MyService
  • MyService: This is the @Service that process the request, it depends on MyDao
  • MyDao: This is the repository class which interact with the database

3.2 Code of MyService and MyDao

MyDao.java

@Component
public class MyDao {

    public String queryHello() {
        return "hello world spring from bswen.com";
    }
}

MyService.java @Service public class MyService { @Autowired private MyDao myDao; //we autowired the instance of MyDao

public String getHello() {
    return myDao.queryHello(); //would throw NullPointerException
} }

3.2 The problematic codes

@Controller
public class MyController {

    @RequestMapping(value="/hello")
    public @ResponseBody
    String hello()  {
        MyService myService = new MyService(); //we create the instance of MyService by new
        return myService.getHello();
    }
}

When we call the api, we got this:

➜  bswen-project git:(master) ✗ curl http://localhost:8080/hello
{"timestamp":"2019-07-01T13:41:52.468+0000","status":500,"error":"Internal Server Error","message":"No message available","path":"/hello"}%   

And we can see the NullPointerException in the logs of the server:

2019-07-01 21:41:52.457 ERROR 2429 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
    at com.bswen.springautowirenull.MyService.getHello(MyService.java:15) ~[classes/:na]
    at com.bswen.springautowirenull.MyController.hello(MyController.java:17) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    ...

3.3 Why did this happen?

Although the field @myDao is @AutoWired in MyService,however,because we create instance of MyService by new instead of Spring, spring didn’t know about the instance of MyService and didn’t know to autowire it.

4 How to solve this problem?

4.1 DO NOT create instance by yourself

You should not create MyService instance by yourself, you can do as follows:

@RequestMapping(value="/hello2")
public @ResponseBody
String hello2()  {
    return myService.getHello();
}

@Autowired
private MyService myService;

Let’s call the api:

➜  bswen-project git:(master) ✗ curl http://localhost:8080/hello2
hello world spring from bswen.com%   

Here we use the @Autowired to inject the instance of MyService, do not create the instance by new.

You can reference this quotes:

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.

5. Summary

If you use Spring framework in your application, just leave the class initialization to spring, do not create instances by yourself.