Reputation: 19
i have created a simple java class in spring boot application. calling a method ns.mesage(); from two different methods but one is executed and another one throw an null pointer exception.
package TestPackage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/*
import TestPackage.MorningService;
import TestPackage.NightService;*/
@RestController
public class GenerateMessage {
@Autowired
public MorningService ms;
@Autowired
public NightService ns;
@RequestMapping(path = "/test")
public String starter(){
GenerateMessage gm=new GenerateMessage();
ns.mesage(); // this call working fine
gm.mes();
return "Mail scheduled.";
}
public void mes(){
try{
System.out.println("starts2..............");
ns.mesage(); // throwing an exception
}catch(Exception e){
e.printStackTrace();
}
}
}
Upvotes: 1
Views: 4980
Reputation: 2687
You must not mix usage of new with Autowired.
Once you're using the new keyword, you're breaking all the injections used with @Autowired(it means that the MorningService and NightService will not be initialized) , that is why you're getting a NPE.
Soulution No.1
use AUTOWIRE
@Autowired
public MorningService ms;
@Autowired
public NightService ns;
@Autowired
GenerateMessage gm;
@RequestMapping(path = "/test")
public String starter(){
// GenerateMessage gm=new GenerateMessage();
ns.mesage(); // this call working fine
gm.mes();
return "Mail scheduled.";
}
Solution No.2
use this keyword
@RequestMapping(path = "/test")
public String starter(){
// GenerateMessage gm=new GenerateMessage();
ns.mesage(); // this call working fine
this.mes();
return "Mail scheduled.";
}
Upvotes: 2
Reputation: 1227
When you create an instance with keyword new, it doesn't go through the spring bean lifecycle. In a result post-processor, which response for processing @Autowired annotation doesn't work, and NightService not injected in new instance of GenerateMessage. You just create an instance of the class with null fields.
If you want to create real bean manually you should do it like this:
@RestController
public class GenerateMessage {
@Autowired
public MorningService ms;
@Autowired
public NightService ns;
@Autowired
private ApplicationContext applicationContext;
@RequestMapping(path = "/test")
public String starter(){
GenerateMessage gm=applicationContext.getBean(GenerateMessage.class);
ns.mesage(); // this call working fine
gm.mes();
return "Mail scheduled.";
}
public void mes(){
try{
System.out.println("starts2..............");
ns.mesage(); // throwing an exception
}catch(Exception e){
e.printStackTrace();
}
}
}
But I do not recommend you to work with the applicationcontext directly, cause it is a heavy object and may lead to decrease performance.
Upvotes: 0
Reputation: 1860
Once you're using the new
keyword, you're breaking all the injections used with @Autowired
(it means that the MorningService
and NightService
will not be initialized) , that is why you're getting a NPE.
If you really want to test your mes()
method from your controller, implement in your @SpringBootApplication
class the CommandLineRunner
interface.
Then you can inject a GenerateMessage
bean with @Autowired
and test your method.
Here is an example:
@SpringBootApplication
public class MainApplication implements CommandLineRunner {
@Autowired
private GenerateMessage generateMessage;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
generateMessage.mes();
}
}
Upvotes: 4