I want to use the getInstance
method of the Guice Injector
class in Play Framework 2.4, how can I access it?
I have used the Guice FactoryModuleBuilder
for implementing a factory that returns another factory at runtime! At the second level of returning a factory I need to access the Play Guice Injector to get objects manually using reflection instead of @Inject
annotation.
There are many ways. I use this one.
Edit: This is relevant for Play versions which are <= 2.4:
Play.maybeApplication.map(_.injector.instanceOf[MyProdClass]).getOrElse(new MyDevClass)
or
Play.current.injector.instanceOf[MyClass]
For versions which are >= 2.5:
import play.api.inject.Injector
import javax.inject.Inject
class MyService @Inject() (injector: Injector) ={
val myClassInstance = injector.instanceOf[MyClass]
//do stuff
}
With Play Framework 2.5.x play.api.Play.current
is deprecated and DI should always be preferred. Therefore proper way of getting injector instance is by using:
import play.api.inject.Injector
import javax.inject.Inject
class SomeClassRequiringInjector @Inject() (injector: Injector) { ... }
Works for me even when doing this with DI Provider class :)
It is better to inject Guice Injector:
@Inject
private Injector injector;
Or you can use this code for Play Framework Java edition:
Play.application().injector().instanceOf(YourClass.class);
Apart from the other Play 2.5.x solutions, there may be a situation in which you want to get the Injector in an object without using injection. For example when you're using a Scala singleton, for which @inject probably doesn't work.
In that case, you can use this:
@Singleton
class GlobalContext @Inject()(injector: Injector) {
GlobalContext.injector = injector
}
object GlobalContext {
private var injector: Injector = null
}
With a Guice module to set the singleton to eager, otherwise it won't be initialized automatically:
// Module.scala
class Module extends AbstractModule {
override def configure() = {
// ...
// Eager initialize Context singleton
bind(classOf[GlobalContext]).asEagerSingleton()
}
}
I really like Devabc's solution because there definitely are some scenarios that can't rely on constructor injection to get the injector itself, instead in Play 2.5.x you have to use the the deprecated play.api.Play.current.Injector
code to get the injector.
His solution create a reference to the Play build-in injector and put it into a Scala object which can be imported by any component when they need to. Brilliant!
In order to make it work, however, the object needs to provide a public interface to get the injector, so here is my amended code to fix it and demo how it can be used.
import play.api.inject.Injector
import javax.inject.Inject
@Singleton
class GlobalContext @Inject()(playInjector: Injector) {
GlobalContext.injectorRef = playInjector
}
object GlobalContext {
private var injectorRef: Injector = _
def injector: Injector = injectorRef
}
The initialization part is the same.
// InjectionModule.scala
package modules
class InjectionModule extends AbstractModule {
override def configure() = {
// ...
// Eager initialize Context singleton
bind(classOf[GlobalContext]).asEagerSingleton()
}
}
// application.conf
play.modules.enabled += "modules.InjectionModule"
And the client code is quite simple. In whichever component requires the injector:
// Import the object GlobalContext
import GlobalContext.injector
// ...
val yourClassInstance = injector.instanceOf[YourClass]