Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get all implementors/subclasses of an interface with Guice?

Tags:

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?

like image 891
Adam Vandenberg Avatar asked May 22 '11 00:05

Adam Vandenberg


People also ask

What is Guice Createinjector?

Class GuiceCreates Injector s from Module s. Guice supports a model of development that draws clear boundaries between APIs, Implementations of these APIs, Modules which configure these implementations, and finally Applications which consist of a collection of Modules.

What is a Guice AbstractModule?

AbstractModule is a helper class used to add bindings to the Guice injector.

What are Guice modules?

The Guice module helps you to inject Guice managed components into your play application. The injection points are defined by the upcoming @javax. inject. Inject annotation, which is bundled with play at the moment.

What is injector in Guice?

Interface Injector. public interface Injector. Builds the graphs of objects that make up your application. The injector tracks the dependencies for each type and uses bindings to inject them. This is the core of Guice, although you rarely interact with it directly.


3 Answers

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.

like image 98
jfpoilpret Avatar answered Dec 17 '22 16:12

jfpoilpret


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.

like image 35
vorburger Avatar answered Dec 17 '22 18:12

vorburger


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>)
like image 23
Niraj Sonawane Avatar answered Dec 17 '22 18:12

Niraj Sonawane