Search code examples
javadependency-injectionplayframeworkguice

How to create and use and instance using guice in java play


I am trying to use guice and I want to create a Singleton of random webservice client in Java Play 2.6

For now I have my WS client and it loads as a java play module. When I run the application, no problem, my client is able to use the java play Configuration (com.typesafe.config.Config), which is injected. But if I try to use my client anywhere else, I get an error saying No implementation for com.typesafe.config.Config was bound .

Here is my (very simple) client :

import play.Logger;
import com.typesafe.config.Config;

@Singleton
public class MyClient {
    final Config config;

    @Inject
    public MyClient(Config config) {
        this.config = config;
        Logger.warn("constructor called")
        Logger.warn("Some config param:"+config.getString("some_param"))
    }

    public void doSomething() {
        Logger.warn("doSomething() called")
    }

}

My Module implementing Guice's AbstractModule :

import com.google.inject.AbstractModule;

public class MyClientModule extends AbstractModule {
    @Override 
    protected void configure() {
        bind(MyClient.class).asEagerSingleton();
    }

}

When I tell Play to use it as a module in applicationf.conf, it works (i get the "Constructor called" and the "Some config param" warning logs in the console):

play {
  modules {
    enabled += external.MyClientModule
  }
}

But If I try to call it from my HomeController :

public class HomeController extends Controller {
    public Result index() {
        Injector myClientInjector = Guice.createInjector(new MyClientModule());
        MyClient myClient = myClientInjector.getInstance(MyClient.class);
        return ok(views.html.index.render());
    }
}

then I get the following error :

[CreationException: Unable to create injector, see the following errors:

1) No implementation for com.typesafe.config.Config was bound.
  while locating com.typesafe.config.Config
    for the 1st parameter of external.MyClient.<init>(MyClient.java:121)
  at external.MyClientModule.configure(MyClientModule.java:8)

1 error]

I'm pretty sure there are a few things wrong here, so what would be the correct way to bind it and then use it ?


Solution

  • In the HomeController, use constructor injection :

    @Inject
    public HomeController (final MyClient myclient) {
        this.myclient = myclient;
    }
    

    You can annotate 1 constructor like this, so it needs to contain all the classes you want to inject. You can combine constructor and field injection, but that is not recommended.