Use Guice multibindings with assisted inject for the set members

狂风中的少年 提交于 2021-02-08 08:41:51

问题


I have a class PluginManager which accepts a Set<Plugin> using the Guice multi-bindings feature. However, the PluginManager has some runtime information that needs to be passed to the Plugin constructor.

This seems to be a perfect use-case for Guice assisted injection i.e. my PluginManager would have Set<PluginFactory> injected, where the runtime information is provided to each factory, resulting in the required Plugin instances.

I don't know the syntax to use in the Module however. The multibinder addBinding does not seem to have any facility to connect the result of FactoryModuleBuilder.

I can create my own custom Factory implementations and multibind that obviously, but is there a way to combine multibinder with assisted inject?


回答1:


I think this gives you an example to do exactly what you want. Please note that scala's multibinder has a pending pull request that allows you to create the set binder in multiple places.

object Test {
  trait Plugin {
    def name(): String
  }

  object Plugin {
    trait Factory[+T <: Plugin] {
      def newPlugin(name: String): T
    }
  }

  case class MyPlugin @Inject() (@Assisted name: String) extends Plugin
  case class OtherPlugin @Inject() (@Assisted name: String) extends Plugin

  class PluginManager @Inject() (pluginFactories: Set[Plugin.Factory[Plugin]]) {
    for (factory <- pluginFactories) {
      println(factory.newPlugin("assisted injection"))
    }
  }

  def main(args: Array[String]): Unit = {
    val injector = Guice.createInjector(new ScalaModule {
      override def configure(): Unit = {
        val plugins = ScalaMultibinder.newSetBinder[Plugin.Factory[Plugin]](binder)
        plugins.addBinding().to[Plugin.Factory[MyPlugin]]
        plugins.addBinding().to[Plugin.Factory[OtherPlugin]]

        bindFactory[Plugin, MyPlugin, Plugin.Factory[MyPlugin]]()
        bindFactory[Plugin, OtherPlugin, Plugin.Factory[OtherPlugin]]()

        bind[PluginManager].asEagerSingleton()
      }

      def bindFactory[I: Manifest, C <: I : Manifest, F: Manifest](): Unit = {
        import net.codingwell.scalaguice._
        install(new FactoryModuleBuilder()
          .implement(typeLiteral[I], typeLiteral[C])
          .build(typeLiteral[F]))
      }
    })
  }
}

You can do a bunch of things depending on the style you want. For example you could make a generic addPlugin method (when a newer version of scala-guice is released) like this:

val injector = Guice.createInjector(new ScalaModule {
  override def configure(): Unit = {
    bindPlugin[MyPlugin]()
    bindPlugin[OtherPlugin]()

    bind[PluginManager].asEagerSingleton()
  }

  def bindPlugin[T <: Plugin : Manifest](): Unit = {
    val plugins = ScalaMultibinder.newSetBinder[Plugin.Factory[T]](binder)
    plugins.addBinding().to[Plugin.Factory[T]]
    bindFactory[Plugin, T, Plugin.Factory[T]]()
  }

  def bindFactory[I: Manifest, C <: I : Manifest, F: Manifest](): Unit = {
    import net.codingwell.scalaguice._
    install(new FactoryModuleBuilder()
      .implement(typeLiteral[I], typeLiteral[C])
      .build(typeLiteral[F]))
  }
})


来源:https://stackoverflow.com/questions/26514009/use-guice-multibindings-with-assisted-inject-for-the-set-members

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!