0

I am creating a simple rest service. I have a rest controller class which has a post mapping endpoint "/insert" :

    @RestController
    @RequestMapping("/restapi")
    public class RestService{

        @PostMapping("/insert")
        public void insert(@RequestBody String body){
            DBClass db = new DBClass();
            db.insert(body);
        }

    }

I got a class called DBClass which connects to the database and inserts objects. But if it fails, it will send an email about the error. Here is the insert method:

public void insertToFirestore(String body) {

        try {
            //insertDB
        } catch (Exception e) {
            MailService ms = new MailService();
            ms.sendMail(to,subject,text);
        }

    }

And there is a MailService class where I do things about mails. It has a method called sendMail :

@Component
public class MailService {

    @Autowired
    JavaMailSender jms;

    public void sendMail(String to,String subject,String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        jms.send(message);
    }
}

I had done the configurations in the application.properties file. So if I try to send mail in the rest controller class it works just fine but when I try to send mail in MailService class Javamailsender object throws null pointer exception. I also tried sending mails other than Rest Controller class and they all threw the same exception.

@Autowired keyword initialize the java mail sender object only in Rest Controller class. What is the reason for that ?

Any help is appreciated.

Yunus Emre Güler
  • 387
  • 1
  • 6
  • 16

2 Answers2

3

Auto-wiring will not work when class is initialized with new keyword. Here in your case you are initializing MailService with new keyword, that's why it will not autowire JavaMailSender inside it.

You can try below code which will work -

@Component
class DBClass {
    @Autowired
    private MailService ms;
    public void insertToFirestore(String body) {

        try {
            //insertDB
        } catch (Exception e) {
            ms.sendMail(to,subject,text);
        }

    }
}


@RestController
@RequestMapping("/restapi")
public class RestService{
@Autowired
private DBClass db;
    @PostMapping("/insert")
    public void insert(@RequestBody String body){
        db.insert(body);
    }

}
Jignesh M. Khatri
  • 1,407
  • 1
  • 14
  • 22
2

The problem is that you are instantiating the DBClass object with new DBClass() instead of creating a Spring bean and inject it in the RestService. Therefore the DBClass instance is not managed by Spring and the JavaMailSender is null.

I would suggest to create a bean for DBClass and autowiring it in the RestService.

E.g:

@RestController
@RequestMapping("/restapi")
public class RestService {

    @Autowired
    private DBClass db;

    @PostMapping("/insert")
    public void insert(@RequestBody String body){
        db.insert(body);
    }

}

Keep in mind that the DBClass needs to be threadsafe if you are creating a Spring bean for it with the default singleton scope.

brass monkey
  • 5,841
  • 10
  • 36
  • 61
  • Thank you for your reply :) I Autowired every variable to reach the MailService class: So DBClass and MailService objects are also autowired . Then it worked. – Yunus Emre Güler Oct 28 '18 at 14:30