PageRenderTime 51ms CodeModel.GetById 30ms app.highlight 18ms RepoModel.GetById 0ms app.codeStats 0ms

/framework/src/play/src/main/scala/play/api/inject/guice/GuiceInjectorBuilder.scala

https://gitlab.com/KiaraGrouwstra/playframework
Scala | 343 lines | 185 code | 48 blank | 110 comment | 2 complexity | 647b0a19afe8714c2e60406979fe682e MD5 | raw file
  1/*
  2 * Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
  3 */
  4package play.api.inject
  5package guice
  6
  7import com.google.inject.util.{ Modules => GuiceModules, Providers => GuiceProviders }
  8import com.google.inject.{ Module => GuiceModule, Stage, CreationException, Guice }
  9import java.io.File
 10import javax.inject.Inject
 11import play.api.inject.{ Binding => PlayBinding, BindingKey, Injector => PlayInjector, Module => PlayModule }
 12import play.api.{ Configuration, Environment, Mode, PlayException }
 13import scala.reflect.ClassTag
 14
 15class GuiceLoadException(message: String) extends RuntimeException(message)
 16
 17/**
 18 * A builder for creating Guice-backed Play Injectors.
 19 */
 20abstract class GuiceBuilder[Self] protected (
 21    environment: Environment,
 22    configuration: Configuration,
 23    modules: Seq[GuiceableModule],
 24    overrides: Seq[GuiceableModule],
 25    disabled: Seq[Class[_]],
 26    eagerly: Boolean) {
 27
 28  /**
 29   * Set the environment.
 30   */
 31  final def in(env: Environment): Self =
 32    copyBuilder(environment = env)
 33
 34  /**
 35   * Set the environment path.
 36   */
 37  final def in(path: File): Self =
 38    copyBuilder(environment = environment.copy(rootPath = path))
 39
 40  /**
 41   * Set the environment mode.
 42   */
 43  final def in(mode: Mode.Mode): Self =
 44    copyBuilder(environment = environment.copy(mode = mode))
 45
 46  /**
 47   * Set the environment class loader.
 48   */
 49  final def in(classLoader: ClassLoader): Self =
 50    copyBuilder(environment = environment.copy(classLoader = classLoader))
 51
 52  /**
 53   * Set the dependency initialization to eager.
 54   */
 55  final def eagerlyLoaded(): Self =
 56    copyBuilder(eagerly = true)
 57
 58  /**
 59   * Add additional configuration.
 60   */
 61  final def configure(conf: Configuration): Self =
 62    copyBuilder(configuration = configuration ++ conf)
 63
 64  /**
 65   * Add additional configuration.
 66   */
 67  final def configure(conf: Map[String, Any]): Self =
 68    configure(Configuration.from(conf))
 69
 70  /**
 71   * Add additional configuration.
 72   */
 73  final def configure(conf: (String, Any)*): Self =
 74    configure(conf.toMap)
 75
 76  /**
 77   * Add Guice modules, Play modules, or Play bindings.
 78   *
 79   * @see [[GuiceableModuleConversions]] for the automatically available implicit
 80   *      conversions to [[GuiceableModule]] from modules and bindings.
 81   */
 82  final def bindings(bindModules: GuiceableModule*): Self =
 83    copyBuilder(modules = modules ++ bindModules)
 84
 85  /**
 86   * Override bindings using Guice modules, Play modules, or Play bindings.
 87   *
 88   * @see [[GuiceableModuleConversions]] for the automatically available implicit
 89   *      conversions to [[GuiceableModule]] from modules and bindings.
 90   */
 91  final def overrides(overrideModules: GuiceableModule*): Self =
 92    copyBuilder(overrides = overrides ++ overrideModules)
 93
 94  /**
 95   * Disable modules by class.
 96   */
 97  final def disable(moduleClasses: Class[_]*): Self =
 98    copyBuilder(disabled = disabled ++ moduleClasses)
 99
100  /**
101   * Disable module by class.
102   */
103  final def disable[T](implicit tag: ClassTag[T]): Self = disable(tag.runtimeClass)
104
105  /**
106   * Create a Play Injector backed by Guice using this configured builder.
107   */
108  def applicationModule(): GuiceModule = createModule
109
110  /**
111   * Creation of the Guice Module used by the injector.
112   * Libraries like Guiceberry and Jukito that want to handle injector creation may find this helpful.
113   */
114  def createModule(): GuiceModule = {
115    import scala.collection.JavaConverters._
116    val injectorModule = GuiceableModule.guice(Seq(
117      bind[PlayInjector].to[GuiceInjector],
118      // Java API injector is bound here so that it's available in both
119      // the default application loader and the Java Guice builders
120      bind[play.inject.Injector].to[play.inject.DelegateInjector]
121    ))
122    val enabledModules = modules.map(_.disable(disabled))
123    val bindingModules = GuiceableModule.guiced(environment, configuration)(enabledModules) :+ injectorModule
124    val overrideModules = GuiceableModule.guiced(environment, configuration)(overrides)
125    GuiceModules.`override`(bindingModules.asJava).`with`(overrideModules.asJava)
126  }
127
128  /**
129   * Create a Play Injector backed by Guice using this configured builder.
130   */
131  def injector(): PlayInjector = {
132    try {
133      val stage = environment.mode match {
134        case Mode.Prod => Stage.PRODUCTION
135        case _ if eagerly => Stage.PRODUCTION
136        case _ => Stage.DEVELOPMENT
137      }
138      val guiceInjector = Guice.createInjector(stage, applicationModule())
139      guiceInjector.getInstance(classOf[PlayInjector])
140    } catch {
141      case e: CreationException => e.getCause match {
142        case p: PlayException => throw p
143        case _ => throw e
144      }
145    }
146  }
147
148  /**
149   * Internal copy method with defaults.
150   */
151  private def copyBuilder(
152    environment: Environment = environment,
153    configuration: Configuration = configuration,
154    modules: Seq[GuiceableModule] = modules,
155    overrides: Seq[GuiceableModule] = overrides,
156    disabled: Seq[Class[_]] = disabled,
157    eagerly: Boolean = eagerly): Self =
158    newBuilder(environment, configuration, modules, overrides, disabled, eagerly)
159
160  /**
161   * Create a new Self for this immutable builder.
162   * Provided by builder implementations.
163   */
164  protected def newBuilder(
165    environment: Environment,
166    configuration: Configuration,
167    modules: Seq[GuiceableModule],
168    overrides: Seq[GuiceableModule],
169    disabled: Seq[Class[_]],
170    eagerly: Boolean): Self
171
172}
173
174/**
175 * Default empty builder for creating Guice-backed Injectors.
176 */
177final class GuiceInjectorBuilder(
178  environment: Environment = Environment.simple(),
179  configuration: Configuration = Configuration.empty,
180  modules: Seq[GuiceableModule] = Seq.empty,
181  overrides: Seq[GuiceableModule] = Seq.empty,
182  disabled: Seq[Class[_]] = Seq.empty,
183  eagerly: Boolean = false) extends GuiceBuilder[GuiceInjectorBuilder](
184  environment, configuration, modules, overrides, disabled, eagerly
185) {
186
187  // extra constructor for creating from Java
188  def this() = this(environment = Environment.simple())
189
190  /**
191   * Create a Play Injector backed by Guice using this configured builder.
192   */
193  def build(): PlayInjector = injector()
194
195  protected def newBuilder(
196    environment: Environment,
197    configuration: Configuration,
198    modules: Seq[GuiceableModule],
199    overrides: Seq[GuiceableModule],
200    disabled: Seq[Class[_]],
201    eagerly: Boolean): GuiceInjectorBuilder =
202    new GuiceInjectorBuilder(environment, configuration, modules, overrides, disabled, eagerly)
203}
204
205/**
206 * Magnet pattern for creating Guice modules from Play modules or bindings.
207 */
208trait GuiceableModule {
209  def guiced(env: Environment, conf: Configuration): Seq[GuiceModule]
210  def disable(classes: Seq[Class[_]]): GuiceableModule
211}
212
213/**
214 * Loading and converting Guice modules.
215 */
216object GuiceableModule extends GuiceableModuleConversions {
217
218  def loadModules(environment: Environment, configuration: Configuration): Seq[GuiceableModule] = {
219    Modules.locate(environment, configuration) map guiceable
220  }
221
222  /**
223   * Attempt to convert a module of unknown type to a GuiceableModule.
224   */
225  def guiceable(module: Any): GuiceableModule = module match {
226    case playModule: PlayModule => fromPlayModule(playModule)
227    case guiceModule: GuiceModule => fromGuiceModule(guiceModule)
228    case unknown => throw new PlayException(
229      "Unknown module type",
230      s"Module [$unknown] is not a Play module or a Guice module"
231    )
232  }
233
234  /**
235   * Apply GuiceableModules to create Guice modules.
236   */
237  def guiced(env: Environment, conf: Configuration)(builders: Seq[GuiceableModule]): Seq[GuiceModule] =
238    builders flatMap { module => module.guiced(env, conf) }
239
240}
241
242/**
243 * Implicit conversions to GuiceableModules.
244 */
245trait GuiceableModuleConversions {
246
247  import scala.language.implicitConversions
248
249  implicit def fromGuiceModule(guiceModule: GuiceModule): GuiceableModule = fromGuiceModules(Seq(guiceModule))
250
251  implicit def fromGuiceModules(guiceModules: Seq[GuiceModule]): GuiceableModule = new GuiceableModule {
252    def guiced(env: Environment, conf: Configuration): Seq[GuiceModule] = guiceModules
253    def disable(classes: Seq[Class[_]]): GuiceableModule = fromGuiceModules(filterOut(classes, guiceModules))
254    override def toString = s"GuiceableModule(${guiceModules.mkString(", ")})"
255  }
256
257  implicit def fromPlayModule(playModule: PlayModule): GuiceableModule = fromPlayModules(Seq(playModule))
258
259  implicit def fromPlayModules(playModules: Seq[PlayModule]): GuiceableModule = new GuiceableModule {
260    def guiced(env: Environment, conf: Configuration): Seq[GuiceModule] = playModules.map(guice(env, conf))
261    def disable(classes: Seq[Class[_]]): GuiceableModule = fromPlayModules(filterOut(classes, playModules))
262    override def toString = s"GuiceableModule(${playModules.mkString(", ")})"
263  }
264
265  implicit def fromPlayBinding(binding: PlayBinding[_]): GuiceableModule = fromPlayBindings(Seq(binding))
266
267  implicit def fromPlayBindings(bindings: Seq[PlayBinding[_]]): GuiceableModule = new GuiceableModule {
268    def guiced(env: Environment, conf: Configuration): Seq[GuiceModule] = Seq(guice(bindings))
269    def disable(classes: Seq[Class[_]]): GuiceableModule = this // no filtering
270    override def toString = s"GuiceableModule(${bindings.mkString(", ")})"
271  }
272
273  private def filterOut[A](classes: Seq[Class[_]], instances: Seq[A]): Seq[A] =
274    instances.filterNot(o => classes.exists(_.isAssignableFrom(o.getClass)))
275
276  /**
277   * Convert the given Play module to a Guice module.
278   */
279  def guice(env: Environment, conf: Configuration)(module: PlayModule): GuiceModule =
280    guice(module.bindings(env, conf))
281
282  /**
283   * Convert the given Play bindings to a Guice module.
284   */
285  def guice(bindings: Seq[PlayBinding[_]]): GuiceModule = {
286    new com.google.inject.AbstractModule {
287      def configure(): Unit = {
288        for (b <- bindings) {
289          val binding = b.asInstanceOf[PlayBinding[Any]]
290          val builder = binder().withSource(binding).bind(GuiceKey(binding.key))
291          binding.target.foreach {
292            case ProviderTarget(provider) => builder.toProvider(GuiceProviders.guicify(provider))
293            case ProviderConstructionTarget(provider) => builder.toProvider(provider)
294            case ConstructionTarget(implementation) => builder.to(implementation)
295            case BindingKeyTarget(key) => builder.to(GuiceKey(key))
296          }
297          (binding.scope, binding.eager) match {
298            case (Some(scope), false) => builder.in(scope)
299            case (None, true) => builder.asEagerSingleton()
300            case (Some(scope), true) => throw new GuiceLoadException("A binding must either declare a scope or be eager: " + binding)
301            case _ => // do nothing
302          }
303        }
304      }
305    }
306  }
307
308}
309
310/**
311 * Conversion from Play BindingKey to Guice Key.
312 */
313object GuiceKey {
314  import com.google.inject.Key
315
316  def apply[T](key: BindingKey[T]): Key[T] = {
317    key.qualifier match {
318      case Some(QualifierInstance(instance)) => Key.get(key.clazz, instance)
319      case Some(QualifierClass(clazz)) => Key.get(key.clazz, clazz)
320      case None => Key.get(key.clazz)
321    }
322  }
323}
324
325/**
326 * Play Injector backed by a Guice Injector.
327 */
328class GuiceInjector @Inject() (injector: com.google.inject.Injector) extends PlayInjector {
329  /**
330   * Get an instance of the given class from the injector.
331   */
332  def instanceOf[T](implicit ct: ClassTag[T]) = instanceOf(ct.runtimeClass.asInstanceOf[Class[T]])
333
334  /**
335   * Get an instance of the given class from the injector.
336   */
337  def instanceOf[T](clazz: Class[T]) = injector.getInstance(clazz)
338
339  /**
340   * Get an instance bound to the given binding key.
341   */
342  def instanceOf[T](key: BindingKey[T]) = injector.getInstance(GuiceKey(key))
343}