Spring Top – Temp

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
Lightrun – Third Party Code
announcement - icon

Flakiness in REST requests is a common issue. A request can get a 200 OK in one scenario and a 409 next time. Sometimes a request can even succeed and fail intermittently on the same exact request. In short, working over HTTP can be a bit of a mess without solid tooling.

Also, while it’s easy enough to debug these issues locally when developing the application, we’re talking about production here - we can’t afford the downtime while you’re stepping in and out of code. Uptime is kind of the whole point.

With Lightrun, you can get the same level of access you get with a local debugger or profiler - no downtime required. You can add logs, metrics, and snapshots (think breakpoints, but without stopping the running service), in a safe and read-only manner - without redeploying, restarting, or even stopping the running service. Performance and security are maintained throughout the process.

Learn how to debug a live REST API (built with Spring, of course), using Lightrun, in this 5-minute tutorial:

>> Debugging REST Requests in Spring-Based applications using the Lightrun Platform

1. Overview

In this tutorial, we'll see common errors that lead to a NullPointerException on an Autowired field. We'll also explain how to fix the problem.

2. Presentation of the Problem

First, let's define a Spring component with an empty doWork method:

@Component
public class MyComponent {
    public void doWork() {}
}

Then, let's define our service class. We'll use Spring capacities to inject a MyComponent bean inside our service so that we can call the doWork method inside the service method:

public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}

Now, let's add a controller which will instantiate a service and call the serve method:

@Controller
public class MyController {
    
    public String control() {
        MyService userService = new MyService();
        return userService.serve();
    }
}

At first glance, our code might look perfectly fine. However, after running the application, calling the control method of our controller will lead to the following exception:

java.lang.NullPointerException: null
  at com.baeldung.autowiring.service.MyService.serve(MyService.java:14)
  at com.baeldung.autowiring.controller.MyController.control(MyController.java:12)

What happened here? When we called the MyService constructor in our controller, we created an object that is not managed by Spring. Having no clue of the existence of this MyService object, Spring is not able to inject a MyComponent bean inside it. Thus, the MyComponent instance inside the MyService object we created will remain null, causing the NullPointerException we get when we try to call a method on this object.

3. Solution

To solve this problem, we have to make the MyService instance used in our controller a Spring-managed Bean.

First, let's tell Spring to generate a Bean for our MyService class. We have various possibilities to achieve this. The easiest one is to decorate the MyService class with the @Component annotation or any of its derivatives. For example, we could do the following:

@Service
public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}

Another alternative to reach the same goal is to add a @Bean method in a @Configuration file:

@Configuration
public class MyServiceConfiguration {

    @Bean
    MyService myService() {
        return new MyService();
    }
}

However, turning MyService class into a Spring-managed bean is not enough. Now, we have to autowire it inside our controller, instead of calling new on it. Let's see how the fixed version of the controller looks:

@Controller
public class MyController {
    
    @Autowired
    MyService myService;
    
    public String control() {
        return myService.serve();
    }
}

Now, calling the control method will return the result of the serve method as expected.

4. Conclusion

In this article, we have seen a very common error that would cause a NullPointerException when we unintentionally mix Spring injection with objects we create by calling their constructors. We fixed the problem by avoiding this responsibility mic-mac and turned the object we used to managed ourselves into a Spring-managed Bean.

As always the code is available over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Generic footer banner
Comments are closed on this article!