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?
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.
AbstractModule is a helper class used to add bindings to the Guice injector.
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.
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.
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.
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
.
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>)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With