Reputation: 24635
If I have interface Validator and multiple implementations for this interface. How can I inject any of the multiple implementations with Guice? Now I know that I can use following code to inject one, but it allows only one implementation:
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(Validator.class).to(OneOfMyValidators.class);
}
}
What I would like to do is:
Validator v1 = injector.getInstance(Validator1.class);
Validator v2 = injector.getInstance(Validator2.class);
Is it possible at all?
Upvotes: 20
Views: 35749
Reputation: 11055
Kotlin
This is how we can do binding for multiple implementations for an interface
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>)
Upvotes: 0
Reputation: 1705
Short answer: binding annotations. They're basically a way of letting the depender give a hint that points towards a particular instance or implementation without requiring a dependency on the full concrete implementation class.
See: https://github.com/google/guice/wiki/BindingAnnotations
For example, in the module, you might do:
bind(Validator.class).annotatedWith(ValidatorOne.class).to(OneOfMyValidators.class);
bind(Validator.class).annotatedWith(ValidatorTwo.class).to(SomeOtherValidator.class);
And in your constructor, you'd do:
@Inject
MyClass(@ValidatorOne Validator someValidator,
@ValidatorTwo Validator otherValidator) {
...
}
To get an annotated value straight from an Injector
, you'll have to use the Guice Key
class, like:
Validator v1 = injector.getInstance(Key.get(Validator.class, ValidatorOne.class));
On a side note, binding annotations are very useful for injecting runtime constants. See the comments for bindConstant
in:
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/Binder.html
Upvotes: 25
Reputation: 4181
I found this thread when looking for a solution for dynamically binding multiple implementations to an interface, similar to ServiceLoader in Java. The answer covers a more general case, but it can also be used to obtain a particular implementation from the set. Multibinder allows to bind multiple implementations to a type:
public class ValidatorsModule extends AbstractModule {
protected void configure() {
Multibinder<Validator> multibinder
= Multibinder.newSetBinder(binder(), Validator.class);
multibinder.addBinding().toInstance(new ValidatorOne());
multibinder.addBinding().toInstance(new ValidatorTwo());
}
}
//Usage
@Inject Set<Validator> validators;
Upvotes: 12
Reputation: 6139
Very similar to ejboy's proposal, but since you own different Validator classes, you can bind to the classes itself, not creating instances manually.
protected void configure() {
...
Multibinder<Validator> mb = Multibinder.newSetBinder(binder(), Validator.class);
mb.addBinding().to(Validator1.class);
mb.addBinding().to(Validator2.class);
mb.addBinding().to(Validator3.class);
...
}
Then viewed from the perspective of usage, e.g. by Constructor Injection:
class UseCase {
private Set<Validator> allOfThem;
@Inject
public UseCase(Set<Validator> allOfThem) {
this.allOfThem = allOfThem;
// e.g. iteratation
for (Validator oneOfThem : allOfThem) {
...
}
}
}
Upvotes: 9