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