24

With Spring, you can define an array property and have Spring inject one of every (@Component) class that derives from the given type.

Is there an equivalent for this in Guice? Or an extension point to add this behavior?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Adam Vandenberg
  • 19,991
  • 9
  • 54
  • 56

3 Answers3

21

This looks like a use case for Guice MultiBinder. You could have something like that:

interface YourInterface {
    ...
}

class A implements YourInterface {
    ...
}

class B implements YourInterface {
    ...
}

class YourModule extends AbstractModule {
    @Override protected void configure() {
        Multibinder.newSetBinder(YourInterface.class).addBinding().to(A.class):
        Multibinder.newSetBinder(YourInterface.class).addBinding().to(B.class):
    }
}

And you can inject a Set<YourInterface> anywhere:

class SomeClass {
    @Inject public SomeClass(Set<YourInterface> allImplementations) {
        ...
    }
}

That should match with what you need.

Peti
  • 1,670
  • 1
  • 20
  • 25
jfpoilpret
  • 10,449
  • 2
  • 28
  • 32
16

Guice Multibindings require you to explicitly addBinding() for A & B to YourInterface. If you would like a more "transparent" (automatic) solution such as what AFAIK Spring offers out-of-the-box, then assuming that Guice already knows about A & B because you already have a binding for A & B elsewhere anyway, even if not explicit but just implicit e.g. through an @Inject somewhere else, then and only then you alternatively could use something like this for auto-discovery (inspired by as done here, based on accessing Guice injector in a Module):

class YourModule extends AbstractModule {
   @Override protected void configure() { }

   @Provides
   @Singleton
   SomeClass getSomeClass(Injector injector) {
       Set<YourInterface> allYourInterfaces = new HashSet<>();
       for (Key<?> key : injector.getAllBindings().keySet()) {
           if (YourInterface.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
            YourInterface yourInterface = (YourInterface) injector.getInstance(key);
            allYourInterfaces.add(yourInterface);
       }
       return new SomeClass(allYourInterfaces);
   }
}

Note again that this approach does NOT require any classpath scanning; it just looks at all already known bindings in the Injector for anything that IS-A YourInterface.

Community
  • 1
  • 1
vorburger
  • 3,439
  • 32
  • 38
  • 1
    I am trying same. But It is not working. http://stackoverflow.com/questions/43705146/get-all-the-instance-subclass-of-trait-using-google-guice – Sky Apr 30 '17 at 10:11
1

Kotlin

Class SomeModule : AbstractModule() {
        
            override fun configure() {
                val myBinder: Multibinder<MyInterface> = Multibinder.newSetBinder(binder(), MyInterface::class.java)
                myBinder.addBinding().to(Implementation1::class.java)
                 myBinder.addBinding().to(Implementation2::class.java)
}

Usage

@Inject constructor(private val someVar:Set<@JvmSuppressWildcards MyInterface>)
Niraj Sonawane
  • 10,225
  • 10
  • 75
  • 104