play-mailer icon indicating copy to clipboard operation
play-mailer copied to clipboard

Inject mailerClient in Global.java

Open rienheuver opened this issue 10 years ago • 4 comments

In my Global.java I'm trying to schedule a task which has to sent an email every now and then based on some parameters. I can't seem to access mailerClient though, because I always get a NullPointerException. Can someone explain what I'm doing wrong? My code looks roughly like this:

public class Global extends GlobalSettings {
   @Inject MailerClient mailerClient;

   public void onStart(Application app) {
       // lines of code
       Runnable showTime = new Runnable() {
          @Override
          public void run() {
             //lines of code
             mailerClient.send(email);
          }
       }
    }
}

I can't seem to figure out what's going wrong, any help is appreciated.

rienheuver avatar Feb 27 '16 15:02 rienheuver

I believe Global is not managed by Guice and therefore you can't use @Inject in this "special" class.

If you are keen to use dependency injection, we are recommending that you move out of your GlobalSettings implementation class as much code as possible. Ideally, you should be able to refactor your code so that it is possible to eliminate your GlobalSettings class altogether.

Source: https://www.playframework.com/documentation/2.4.x/GlobalSettings#Java

Instead I think you should create a @Singleton eagerly: https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection#Eager-bindings

ggrossetie avatar Feb 27 '16 18:02 ggrossetie

Create service to send email, something like :

@Singleton
public final class EmailService extends BaseService {
    private final MailerClient mailerClient;
    private final Configuration configuration;

    @Inject
    private final ActorSystem system;

    @Inject
    public EmailService(final Configuration configuration, MailerClient mailerClient, ActorSystem system) {
        this.mailerClient = mailerClient;
        this.configuration = configuration;
        this.system = system;
    }

    public void sendMail(String receiver, String body, String subject, String replyTo, String senderName) {
        system.scheduler().scheduleOnce(
                Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
                () -> {
                    try {
                        Logger.info(String.format("Emailing (%s) from (%s) with subject (%s)", receiver, senderName, subject));
                        Email email = new Email();
                        email.setSubject(subject);
                        email.setReplyTo(replyTo);
                        email.setFrom(senderName + "<" + configuration.getString("play.mailer.from") + ">");
                        email.addTo(receiver);
                        email.setBodyHtml(body);
                        mailerClient.send(email);
                        Logger.info(String.format("Email sent to (%s) from (%s) with subject (%s)", receiver, senderName, subject));
                    } catch (Exception ex) {
                        Logger.error(ex.getMessage());
                    }

                },
                system.dispatcher()
        );
    }
}

And replace Global.java file into this: http://stackoverflow.com/questions/35842293/java-playframework-globalsettings-deprecation-for-onstart

Inside your OnStartup class constructor:

    @Inject
    public OnStartup(final ActorSystem system, final EmailService emailService) {
        // here you can use emailService.sendEmail method.
    }

This is how I'm working with email service if I use it while application start up. if you want to use it in another service or controllers After you started application, just enough to have it as global variable:

@Inject
private MailerClient mailerClient;

almothafar avatar Jun 01 '16 13:06 almothafar

Create service to send email, something like :

@Singleton
public final class EmailService extends BaseService {
    private final MailerClient mailerClient;
    private final Configuration configuration;

    @Inject
    private final ActorSystem system;

    @Inject
    public EmailService(final Configuration configuration, MailerClient mailerClient, ActorSystem system) {
        this.mailerClient = mailerClient;
        this.configuration = configuration;
        this.system = system;
    }

    public void sendMail(String receiver, String body, String subject, String replyTo, String senderName) {
        system.scheduler().scheduleOnce(
                Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
                () -> {
                    try {
                        Logger.info(String.format("Emailing (%s) from (%s) with subject (%s)", receiver, senderName, subject));
                        Email email = new Email();
                        email.setSubject(subject);
                        email.setReplyTo(replyTo);
                        email.setFrom(senderName + "<" + configuration.getString("play.mailer.from") + ">");
                        email.addTo(receiver);
                        email.setBodyHtml(body);
                        mailerClient.send(email);
                        Logger.info(String.format("Email sent to (%s) from (%s) with subject (%s)", receiver, senderName, subject));
                    } catch (Exception ex) {
                        Logger.error(ex.getMessage());
                    }

                },
                system.dispatcher()
        );
    }
}

And replace Global.java file into this: http://stackoverflow.com/questions/35842293/java-playframework-globalsettings-deprecation-for-onstart

Inside your OnStartup class constructor:

    @Inject
    public OnStartup(final ActorSystem system, final EmailService emailService) {
        // here you can use emailService.sendEmail method.
    }

This is how I'm working with email service if I use it while application start up. if you want to use it in another service or controllers After you started application, just enough to have it as global variable:

@Inject
private MailerClient mailerClient;

Which library is used for BaseService?

IntelliJ imported com.google.cloud.BaseService, but I got the error There is no default constructor available in 'com.google.cloud.BaseService'. After making the constructor by adding super();, I got 'BaseService(com.google.cloud.ServiceOptions)' in 'com.google.cloud.BaseService' cannot be applied to '()'. And super takes in com.google.cloud.ServiceOptions

gill876 avatar Mar 24 '22 06:03 gill876

Which library is used for BaseService?

IntelliJ imported com.google.cloud.BaseService, but I got the error There is no default constructor available in 'com.google.cloud.BaseService'. After making the constructor by adding super();, I got 'BaseService(com.google.cloud.ServiceOptions)' in 'com.google.cloud.BaseService' cannot be applied to '()'. And super takes in com.google.cloud.ServiceOptions

Oh you don't mind this, remove it, I had a structure for my services, so it is my own abstract class BaseService

almothafar avatar Mar 29 '22 20:03 almothafar

Solution was posted, Global.java is long gone from Play.

mkurz avatar Jul 21 '23 11:07 mkurz