PageRenderTime 87ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/core/play-guice/src/main/scala/play/api/inject/guice/GuiceInjectorBuilder.scala

https://github.com/playframework/playframework
Scala | 463 lines | 261 code | 55 blank | 147 comment | 4 complexity | 458abdbde6e84741f4b56b0a34b6a0a9 MD5 | raw file
  1. /*
  2. * Copyright (C) Lightbend Inc. <https://www.lightbend.com>
  3. */
  4. package play.api.inject
  5. package guice
  6. import com.google.inject.util.{ Modules => GuiceModules }
  7. import com.google.inject.util.{ Providers => GuiceProviders }
  8. import com.google.inject.Binder
  9. import com.google.inject.CreationException
  10. import com.google.inject.Guice
  11. import com.google.inject.Stage
  12. import com.google.inject.{ Module => GuiceModule }
  13. import java.io.File
  14. import javax.inject.Inject
  15. import javax.inject.Provider
  16. import play.api.inject.{ Binding => PlayBinding }
  17. import play.api.inject.{ Injector => PlayInjector }
  18. import play.api.inject.{ Module => PlayModule }
  19. import play.api.Configuration
  20. import play.api.Environment
  21. import play.api.Mode
  22. import play.api.PlayException
  23. import scala.jdk.CollectionConverters._
  24. import scala.reflect.ClassTag
  25. class GuiceLoadException(message: String) extends RuntimeException(message)
  26. /**
  27. * A builder for creating Guice-backed Play Injectors.
  28. */
  29. abstract class GuiceBuilder[Self] protected (
  30. environment: Environment,
  31. configuration: Configuration,
  32. modules: Seq[GuiceableModule],
  33. overrides: Seq[GuiceableModule],
  34. disabled: Seq[Class[_]],
  35. binderOptions: Set[BinderOption],
  36. eagerly: Boolean
  37. ) {
  38. import BinderOption._
  39. /**
  40. * Set the environment.
  41. */
  42. final def in(env: Environment): Self =
  43. copyBuilder(environment = env)
  44. /**
  45. * Set the environment path.
  46. */
  47. final def in(path: File): Self =
  48. copyBuilder(environment = environment.copy(rootPath = path))
  49. /**
  50. * Set the environment mode.
  51. */
  52. final def in(mode: Mode): Self =
  53. copyBuilder(environment = environment.copy(mode = mode))
  54. /**
  55. * Set the environment class loader.
  56. */
  57. final def in(classLoader: ClassLoader): Self =
  58. copyBuilder(environment = environment.copy(classLoader = classLoader))
  59. /**
  60. * Set the dependency initialization to eager.
  61. */
  62. final def eagerlyLoaded(): Self =
  63. copyBuilder(eagerly = true)
  64. /**
  65. * Add additional configuration.
  66. */
  67. final def configure(conf: Configuration): Self =
  68. copyBuilder(configuration = conf.withFallback(configuration))
  69. /**
  70. * Add additional configuration.
  71. */
  72. final def configure(conf: Map[String, Any]): Self =
  73. configure(Configuration.from(conf))
  74. /**
  75. * Add additional configuration.
  76. */
  77. final def configure(conf: (String, Any)*): Self =
  78. configure(conf.toMap)
  79. private def withBinderOption(opt: BinderOption, enabled: Boolean = false): Self = {
  80. copyBuilder(binderOptions = if (enabled) binderOptions + opt else binderOptions - opt)
  81. }
  82. /**
  83. * Disable circular proxies on the Guice Binder. Without this option, Guice will try to proxy interfaces/traits to
  84. * break a circular dependency.
  85. *
  86. * Circular proxies are disabled by default. Use disableCircularProxies(false) to allow circular proxies.
  87. */
  88. final def disableCircularProxies(disable: Boolean = true): Self =
  89. withBinderOption(DisableCircularProxies, disable)
  90. /**
  91. * Requires that Guice finds an exactly matching binding annotation.
  92. *
  93. * Disables the error-prone feature in Guice where it can substitute a binding for @Named Foo when injecting @Named("foo") Foo.
  94. *
  95. * This option is disabled by default.``
  96. */
  97. final def requireExactBindingAnnotations(require: Boolean = true): Self =
  98. withBinderOption(RequireExactBindingAnnotations, require)
  99. /**
  100. * Require @Inject on constructors (even default constructors).
  101. *
  102. * This option is disabled by default.
  103. */
  104. final def requireAtInjectOnConstructors(require: Boolean = true): Self =
  105. withBinderOption(RequireAtInjectOnConstructors, require)
  106. /**
  107. * Instructs the injector to only inject classes that are explicitly bound in a module.
  108. *
  109. * This option is disabled by default.
  110. */
  111. final def requireExplicitBindings(require: Boolean = true): Self =
  112. withBinderOption(RequireExplicitBindings, require)
  113. /**
  114. * Add Guice modules, Play modules, or Play bindings.
  115. *
  116. * @see [[GuiceableModuleConversions]] for the automatically available implicit
  117. * conversions to [[GuiceableModule]] from modules and bindings.
  118. */
  119. final def bindings(bindModules: GuiceableModule*): Self =
  120. copyBuilder(modules = modules ++ bindModules)
  121. /**
  122. * Override bindings using Guice modules, Play modules, or Play bindings.
  123. *
  124. * @see [[GuiceableModuleConversions]] for the automatically available implicit
  125. * conversions to [[GuiceableModule]] from modules and bindings.
  126. */
  127. final def overrides(overrideModules: GuiceableModule*): Self =
  128. copyBuilder(overrides = overrides ++ overrideModules)
  129. /**
  130. * Disable modules by class.
  131. */
  132. final def disable(moduleClasses: Class[_]*): Self =
  133. copyBuilder(disabled = disabled ++ moduleClasses)
  134. /**
  135. * Disable module by class.
  136. */
  137. final def disable[T](implicit tag: ClassTag[T]): Self = disable(tag.runtimeClass)
  138. /**
  139. * Create a Play Injector backed by Guice using this configured builder.
  140. */
  141. def applicationModule(): GuiceModule = createModule()
  142. /**
  143. * Creation of the Guice Module used by the injector.
  144. * Libraries like Guiceberry and Jukito that want to handle injector creation may find this helpful.
  145. */
  146. def createModule(): GuiceModule = {
  147. import scala.jdk.CollectionConverters._
  148. val injectorModule = GuiceableModule.guice(
  149. Seq(
  150. bind[GuiceInjector].toSelf,
  151. bind[GuiceClassLoader].to(new GuiceClassLoader(environment.classLoader)),
  152. bind[PlayInjector].toProvider[GuiceInjectorWithClassLoaderProvider],
  153. // Java API injector is bound here so that it's available in both
  154. // the default application loader and the Java Guice builders
  155. bind[play.inject.Injector].to[play.inject.DelegateInjector]
  156. ),
  157. binderOptions
  158. )
  159. val enabledModules = modules.map(_.disable(disabled))
  160. val bindingModules = GuiceableModule.guiced(environment, configuration, binderOptions)(enabledModules) :+ injectorModule
  161. val overrideModules = GuiceableModule.guiced(environment, configuration, binderOptions)(overrides)
  162. GuiceModules.`override`(bindingModules.asJava).`with`(overrideModules.asJava)
  163. }
  164. /**
  165. * Create a Play Injector backed by Guice using this configured builder.
  166. */
  167. def injector(): PlayInjector = {
  168. try {
  169. val stage = environment.mode match {
  170. case Mode.Prod => Stage.PRODUCTION
  171. case _ if eagerly => Stage.PRODUCTION
  172. case _ => Stage.DEVELOPMENT
  173. }
  174. val guiceInjector = Guice.createInjector(stage, applicationModule())
  175. guiceInjector.getInstance(classOf[PlayInjector])
  176. } catch {
  177. case e: CreationException =>
  178. e.getCause match {
  179. case p: PlayException => throw p
  180. case _ => {
  181. e.getErrorMessages.asScala.foreach(_.getCause match {
  182. case p: PlayException => throw p
  183. case _ => // do nothing
  184. })
  185. throw e
  186. }
  187. }
  188. }
  189. }
  190. /**
  191. * Internal copy method with defaults.
  192. */
  193. private def copyBuilder(
  194. environment: Environment = environment,
  195. configuration: Configuration = configuration,
  196. modules: Seq[GuiceableModule] = modules,
  197. overrides: Seq[GuiceableModule] = overrides,
  198. disabled: Seq[Class[_]] = disabled,
  199. binderOptions: Set[BinderOption] = binderOptions,
  200. eagerly: Boolean = eagerly
  201. ): Self =
  202. newBuilder(environment, configuration, modules, overrides, disabled, binderOptions, eagerly)
  203. /**
  204. * Create a new Self for this immutable builder.
  205. * Provided by builder implementations.
  206. */
  207. protected def newBuilder(
  208. environment: Environment,
  209. configuration: Configuration,
  210. modules: Seq[GuiceableModule],
  211. overrides: Seq[GuiceableModule],
  212. disabled: Seq[Class[_]],
  213. binderOptions: Set[BinderOption],
  214. eagerly: Boolean
  215. ): Self
  216. }
  217. /**
  218. * Default empty builder for creating Guice-backed Injectors.
  219. */
  220. final class GuiceInjectorBuilder(
  221. environment: Environment = Environment.simple(),
  222. configuration: Configuration = Configuration.empty,
  223. modules: Seq[GuiceableModule] = Seq.empty,
  224. overrides: Seq[GuiceableModule] = Seq.empty,
  225. disabled: Seq[Class[_]] = Seq.empty,
  226. binderOptions: Set[BinderOption] = BinderOption.defaults,
  227. eagerly: Boolean = false
  228. ) extends GuiceBuilder[GuiceInjectorBuilder](
  229. environment,
  230. configuration,
  231. modules,
  232. overrides,
  233. disabled,
  234. binderOptions,
  235. eagerly
  236. ) {
  237. // extra constructor for creating from Java
  238. def this() = this(environment = Environment.simple())
  239. /**
  240. * Create a Play Injector backed by Guice using this configured builder.
  241. */
  242. def build(): PlayInjector = injector()
  243. protected def newBuilder(
  244. environment: Environment,
  245. configuration: Configuration,
  246. modules: Seq[GuiceableModule],
  247. overrides: Seq[GuiceableModule],
  248. disabled: Seq[Class[_]],
  249. binderOptions: Set[BinderOption],
  250. eagerly: Boolean
  251. ): GuiceInjectorBuilder =
  252. new GuiceInjectorBuilder(environment, configuration, modules, overrides, disabled, binderOptions, eagerly)
  253. }
  254. /**
  255. * Magnet pattern for creating Guice modules from Play modules or bindings.
  256. */
  257. trait GuiceableModule {
  258. def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption]): Seq[GuiceModule]
  259. def disable(classes: Seq[Class[_]]): GuiceableModule
  260. }
  261. /**
  262. * Loading and converting Guice modules.
  263. */
  264. object GuiceableModule extends GuiceableModuleConversions {
  265. def loadModules(environment: Environment, configuration: Configuration): Seq[GuiceableModule] = {
  266. Modules.locate(environment, configuration).map(guiceable)
  267. }
  268. /**
  269. * Attempt to convert a module of unknown type to a GuiceableModule.
  270. */
  271. def guiceable(module: Any): GuiceableModule = module match {
  272. case playModule: PlayModule => fromPlayModule(playModule)
  273. case guiceModule: GuiceModule => fromGuiceModule(guiceModule)
  274. case unknown =>
  275. throw new PlayException(
  276. "Unknown module type",
  277. s"Module [$unknown] is not a Play module or a Guice module"
  278. )
  279. }
  280. /**
  281. * Apply GuiceableModules to create Guice modules.
  282. */
  283. def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption])(
  284. builders: Seq[GuiceableModule]
  285. ): Seq[GuiceModule] =
  286. builders.flatMap { module =>
  287. module.guiced(env, conf, binderOptions)
  288. }
  289. }
  290. /**
  291. * Implicit conversions to GuiceableModules.
  292. */
  293. trait GuiceableModuleConversions {
  294. import scala.language.implicitConversions
  295. implicit def fromGuiceModule(guiceModule: GuiceModule): GuiceableModule = fromGuiceModules(Seq(guiceModule))
  296. implicit def fromGuiceModules(guiceModules: Seq[GuiceModule]): GuiceableModule = new GuiceableModule {
  297. def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption]): Seq[GuiceModule] = guiceModules
  298. def disable(classes: Seq[Class[_]]): GuiceableModule = fromGuiceModules(filterOut(classes, guiceModules))
  299. override def toString = s"GuiceableModule(${guiceModules.mkString(", ")})"
  300. }
  301. implicit def fromPlayModule(playModule: PlayModule): GuiceableModule = fromPlayModules(Seq(playModule))
  302. implicit def fromPlayModules(playModules: Seq[PlayModule]): GuiceableModule = new GuiceableModule {
  303. def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption]): Seq[GuiceModule] =
  304. playModules.map(guice(env, conf, binderOptions))
  305. def disable(classes: Seq[Class[_]]): GuiceableModule = fromPlayModules(filterOut(classes, playModules))
  306. override def toString = s"GuiceableModule(${playModules.mkString(", ")})"
  307. }
  308. implicit def fromPlayBinding(binding: PlayBinding[_]): GuiceableModule = fromPlayBindings(Seq(binding))
  309. implicit def fromPlayBindings(bindings: Seq[PlayBinding[_]]): GuiceableModule = new GuiceableModule {
  310. def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption]): Seq[GuiceModule] =
  311. Seq(guice(bindings, binderOptions))
  312. def disable(classes: Seq[Class[_]]): GuiceableModule = this // no filtering
  313. override def toString = s"GuiceableModule(${bindings.mkString(", ")})"
  314. }
  315. private def filterOut[A](classes: Seq[Class[_]], instances: Seq[A]): Seq[A] =
  316. instances.filterNot(o => classes.exists(_.isAssignableFrom(o.getClass)))
  317. /**
  318. * Convert the given Play module to a Guice module.
  319. */
  320. def guice(env: Environment, conf: Configuration, binderOptions: Set[BinderOption])(module: PlayModule): GuiceModule =
  321. guice(module.bindings(env, conf).toSeq, binderOptions)
  322. /**
  323. * Convert the given Play bindings to a Guice module.
  324. */
  325. def guice(bindings: Seq[PlayBinding[_]], binderOptions: Set[BinderOption]): GuiceModule = {
  326. new com.google.inject.AbstractModule {
  327. override def configure(): Unit = {
  328. binderOptions.foreach(_(binder))
  329. for (b <- bindings) {
  330. val binding = b.asInstanceOf[PlayBinding[Any]]
  331. val builder = binder().withSource(binding).bind(GuiceKey(binding.key))
  332. binding.target.foreach {
  333. case ProviderTarget(provider) => builder.toProvider(GuiceProviders.guicify(provider))
  334. case ProviderConstructionTarget(provider) => builder.toProvider(provider)
  335. case ConstructionTarget(implementation) => builder.to(implementation)
  336. case BindingKeyTarget(key) => builder.to(GuiceKey(key))
  337. }
  338. (binding.scope, binding.eager) match {
  339. case (Some(scope), false) => builder.in(scope)
  340. case (None, true) => builder.asEagerSingleton()
  341. case (Some(scope), true) =>
  342. throw new GuiceLoadException("A binding must either declare a scope or be eager: " + binding)
  343. case _ => // do nothing
  344. }
  345. }
  346. }
  347. }
  348. }
  349. }
  350. sealed abstract class BinderOption(configureBinder: Binder => Unit) extends (Binder => Unit) {
  351. def apply(b: Binder) = configureBinder(b)
  352. }
  353. object BinderOption {
  354. val defaults: Set[BinderOption] = Set(DisableCircularProxies)
  355. case object DisableCircularProxies extends BinderOption(_.disableCircularProxies)
  356. case object RequireAtInjectOnConstructors extends BinderOption(_.requireAtInjectOnConstructors)
  357. case object RequireExactBindingAnnotations extends BinderOption(_.requireExactBindingAnnotations)
  358. case object RequireExplicitBindings extends BinderOption(_.requireExplicitBindings)
  359. }
  360. /**
  361. * Conversion from Play BindingKey to Guice Key.
  362. */
  363. object GuiceKey {
  364. import com.google.inject.Key
  365. def apply[T](key: BindingKey[T]): Key[T] = {
  366. key.qualifier match {
  367. case Some(QualifierInstance(instance)) => Key.get(key.clazz, instance)
  368. case Some(QualifierClass(clazz)) => Key.get(key.clazz, clazz)
  369. case None => Key.get(key.clazz)
  370. }
  371. }
  372. }
  373. /**
  374. * Play Injector backed by a Guice Injector.
  375. */
  376. class GuiceInjector @Inject() (injector: com.google.inject.Injector) extends PlayInjector {
  377. /**
  378. * Get an instance of the given class from the injector.
  379. */
  380. def instanceOf[T](implicit ct: ClassTag[T]) = instanceOf(ct.runtimeClass.asInstanceOf[Class[T]])
  381. /**
  382. * Get an instance of the given class from the injector.
  383. */
  384. def instanceOf[T](clazz: Class[T]) = injector.getInstance(clazz)
  385. /**
  386. * Get an instance bound to the given binding key.
  387. */
  388. def instanceOf[T](key: BindingKey[T]) = injector.getInstance(GuiceKey(key))
  389. }
  390. /**
  391. * An object that holds a `ClassLoader` for Guice to use. We use this
  392. * simple value object so it can be looked up by its type when we're
  393. * assembling the Guice injector.
  394. *
  395. * @param classLoader The wrapped `ClassLoader`.
  396. */
  397. class GuiceClassLoader(val classLoader: ClassLoader)
  398. /**
  399. * A provider for a Guice injector that wraps the injector to ensure
  400. * it uses the correct `ClassLoader`.
  401. *
  402. * @param injector The injector to wrap.
  403. * @param guiceClassLoader The `ClassLoader` the injector should use.
  404. */
  405. class GuiceInjectorWithClassLoaderProvider @Inject() (injector: GuiceInjector, guiceClassLoader: GuiceClassLoader)
  406. extends Provider[Injector] {
  407. override def get(): PlayInjector = new ContextClassLoaderInjector(injector, guiceClassLoader.classLoader)
  408. }