By chrylis


2013-11-11 00:05:03 8 Comments

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

13 comments

@yglodt 2019-01-11 15:55: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.

@Ravi Durairaj 2016-07-26 09:25:46

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

@Robert Greathouse 2017-09-19 17:27:18

This is the answer. Because you're instantiating a new MilageFeeCalculator on your own, Spring isn't involved in the instantiation, so Spring spring has no knowledge the object exists. Thus, it can't do anything to it, like inject dependencies.

@Alireza Fattahi 2016-06-11 15:15:25

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!

@nobar 2018-04-12 18:25:12

If this is happening in a test class, make sure you haven't forgotten to annotate the class.

For example, in Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
    ....

@Deepak 2015-10-08 09:17:18

Your problem is new (object creation in java style)

MileageFeeCalculator calc = new MileageFeeCalculator();

With annotation @Service, @Component, @Configuration beans are created in the
application context of Spring when server is started. But when we create objects using new operator the object is not registered in application context which is already created. For Example Employee.java class i have used.

Check this out:

public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    String name = "tenant";
    System.out.println("Bean factory post processor is initialized"); 
    beanFactory.registerScope("employee", new Employee());

    Assert.state(beanFactory instanceof BeanDefinitionRegistry,
            "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        if (name.equals(definition.getScope())) {
            BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
            registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
        }
    }
}

}

@62mkv 2017-10-12 04:43:48

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:

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 )

@ForNeVeR 2017-10-12 04:55:00

That answer is the explanation. <context:component-scan/> implicitly enables <context:annotation-config/> necessary for the @Autowired to work.

@msucil 2017-01-10 18:00:26

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.

@Ralph Callaway 2018-12-05 05:33:43

ran into this when i forgot to add <context:component-scan base-package="com.mypackage"/> to my beans.xml file

@apandey846 2016-10-13 18:41:13

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

@CruelEngine 2018-03-05 12:58:25

this worked for me bu t can you please elaborate on how this is solving the issue ?

@apandey846 2018-04-11 08:45:39

@CruelEngine, look this is constructor injection (where you explicitly setting an object) instead of just using field injection (this is mostly done by spring configuration mostly). So if you are creating a object of ClassB using "new" operator is some other scope then that would not be visible or autowired set for ClassA. Hence, while calling classB.useClassAObjectHere() would throw NPE as classA object was not autowired if you just declare field Injection. Read chrylis is trying to explain same. And this why constructor injection is recommended over field injection. Does it make sense now ?

@CruelEngine 2018-04-11 12:28:49

now i get it . thanks :)

@smwikipedia 2015-11-12 13:41:30

I once encountered the same issue when I was not quite used to the life in the IoC world. The @Autowired field of one of my beans is null at runtime.

The root cause is, instead of using the auto-created bean maintained by the Spring IoC container (whose @Autowired field is indeed properly injected), I am newing my own instance of that bean type and using it. Of course this one's @Autowired field is null because Spring has no chance to inject it.

@chrylis 2013-11-11 00:05:03

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

@Donal Fellows 2013-11-11 00:12:22

The other thing to look at is making objects for beans in a @Configuration bean, where the method to make an instance of a particular bean class is annotated with @Bean.

@chrylis 2013-11-11 00:16:55

@DonalFellows I'm not entirely sure what you're talking about ("making" is ambiguous). Are you talking about a problem with multiple calls to @Bean methods when using Spring Proxy AOP?

@Theo 2014-07-14 22:00:57

Hi there, I am running into a similar issue, however when I use your first suggestion, my application thinks "calc" is null when calling the "mileageFee" method. It's as if it never initializes the @Autowired MileageFeeCalculator calc. Any thoughts?

@Sotirios Delimanolis 2014-10-18 01:39:11

I think you should add an entry at the top of your answer that explains that retrieving the first bean, the root from which you do everything, should be done through the ApplicationContext. Some users (for which I've closed as duplicates) don't understand this.

@chrylis 2014-10-18 02:40:24

@SotiriosDelimanolis Please explain the issue; I'm not sure exactly what point you're making.

@Sotirios Delimanolis 2014-10-18 02:45:43

For non web-app examples (and some times for), if you want to use the bean object tree, you need to access some bean through the ApplicationContext. That is the entry point to a Spring application. I've seen questions where users define their XML (or other) configs but fail to define the container. They just expect the an object created through new to be managed. When you explain to them that this isn't a bean and they need to get it from the context, they don't understand.

@chrylis 2014-10-18 07:05:45

@SotiriosDelimanolis I'll munch on that. It's a good point, but this answer is already a bit unwieldy, and it doesn't mention either constructor injection, which avoids this problem entirely, or Spring Boot. I'll try to figure out how to rework it.

@OO7 2015-03-26 13:43:29

Spring doesn't know about the copy of MileageFeeCalculator that you created with new and didn't know to autowire it this sentence solves my problem. Plus one for this.

@Priidu Neemre 2015-09-03 12:42:10

Correct me if I'm wrong but specifying both the @Service and @Configurable annotations on the MilegageFeeCalculator might be incorrect, as per the Spring AOP documentation: ...make sure that you do not use @Configurable on bean classes which are registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the aspect. So in essence, you should only pick one of them.

@chrylis 2015-09-03 14:04:30

@PriiduNeemre The problem in this usual case is that the programmer isn't registering the Java object as a Spring bean. Yes, this would be inefficient, but it shouldn't produce incorrect behavior, just suboptimal. I'm meaning to update this to recommend constructor injection anyhow.

@kiltek 2018-11-07 12:47:40

Regarding the "Use @Configurable" solution: I have to use Gradle as the build tool. Is it possbile to incorporate the compile-time weaving somehow into Gradle?

@Shirish Coolkarni 2014-04-22 06:47:26

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

    }

}

@Ashish 2014-12-29 11:30:10

hi , I gone through your solution, that's correct . And Here I would like to know " Why we don't create instance of annotated class using new operator, may I know the reason behind that.

@Shirish Coolkarni 2015-08-20 03:04:35

if u create the object using new, u will be handling the life cycle of the bean which contradicts the concept of IOC. We need to ask the container to do it, which does it in a better way

@bluish 2015-05-14 12:44:17

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.

@chrylis 2015-05-14 13:06:02

This pattern is necessary to make Spring beans accessible to legacy code but should be avoided in new code.

@Ondrej Bozek 2015-04-21 11:35:59

Another solution would be putting call: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
To MileageFeeCalculator constructor like this:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

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

@chrylis 2015-04-21 12:41:05

This uses unsafe publication.

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] What is a serialVersionUID and why should I use it?

23 Answered Questions

10 Answered Questions

61 Answered Questions

[SOLVED] Avoiding != null statements

8 Answered Questions

[SOLVED] Why is subtracting these two times (in 1927) giving a strange result?

  • 2011-07-27 08:15:58
  • Freewind
  • 578742 View
  • 6258 Score
  • 8 Answer
  • Tags:   java date timezone

31 Answered Questions

18 Answered Questions

[SOLVED] Why is char[] preferred over String for passwords?

24 Answered Questions

24 Answered Questions

[SOLVED] How to determine if variable is 'undefined' or 'null'?

7 Answered Questions

[SOLVED] Is null check needed before calling instanceof?

Sponsored Content