Get All the instance subclass of trait using Googl

2019-05-30 04:36发布

I am trying to get All the instances subclass of trait(interface). This trait have multiple implementation which are provided third party users.

Is this possible to get All the instances subclasses without explicit binding because I don't have control, Implementation provided by third party users. ?

I already saw the same question in which you need to bind explicitly.

Code sample:

import javax.inject.Inject

import com.google.inject._

import scala.collection.JavaConversions._


object DemoApp extends App {
  val injector = Guice.createInjector(new AllImplModule)
  injector.getInstance(classOf[Action]).perform()


}

class Action @Inject()(impls: List[B]) {

  def perform() = {
    impls.foreach(b => println(b.name))
  }

}

class AllImplModule extends AbstractModule {
  override def configure() = {
    bind(classOf[Action]).asEagerSingleton()
  }

  @Provides
  @Singleton
  def getAllImpls(injector: Injector): List[B] = {
    injector.getAllBindings().keySet().collect {
      case key: Key[_] if (classOf[B].isAssignableFrom(key.getTypeLiteral().getRawType())) =>
        injector.getInstance(key).asInstanceOf[B]
    }.toList

  }
}

trait B {
  def name: String
}

class C1 extends B {
  override def name: String = "C1"

}


class C2 extends B {
  override def name: String = "C2"
}

This is not working. Any help would be appreciated!

2条回答
姐就是有狂的资本
2楼-- · 2019-05-30 05:01

You can inject multiple implementations of the trait using guice-multibindings extension.

Add "com.google.inject.extensions" % "guice-multibindings" % "4.1.0" to your build.sbt file

In the Play module define your bindings like this:

 val multipleBinder = Multibinder.newSetBinder(binder(),classOf[BaseTrait])
 multipleBinder.addBinding().to(classOf[Implementation1])
 multipleBinder.addBinding().to(classOf[Implementation2])

In the component when you want to inject your multiple bindings declare the dependency in this way:

baseTraits: java.util.Set[BaseTrait]

Then it should work.

查看更多
成全新的幸福
3楼-- · 2019-05-30 05:03

Your example code looks ok. Here is a Scala worksheet that dynamically finds all bound implementations of a certain abstract class/trait

import com.google.inject.{AbstractModule, Guice}
import scala.collection.JavaConverters._

trait Foo {
    def name: String
}
class Foo1 extends Foo {
    override def name = "Foo1"
}
class Foo2 extends Foo {
    override def name = "Foo2"
}

val testModule = new AbstractModule {
    override def configure(): Unit = {
        bind(classOf[Foo1]).toInstance(new Foo1)
        bind(classOf[Foo2]).toInstance(new Foo2)
        bind(classOf[Int]).toInstance(42)
    }
}

val injector = Guice.createInjector(testModule)

private def bindingsFor[T](c: Class[T]): Iterable[T] = injector.getAllBindings.asScala.keys
    .filter { key ⇒ c.isAssignableFrom(key.getTypeLiteral.getRawType) }
    .map { key ⇒ injector.getInstance(key).asInstanceOf[T] }

bindingsFor(classOf[Foo]).map(_.name).mkString(", ")

Returns:

output: String = Foo1, Foo2
查看更多
登录 后发表回答