Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice and interface that has multiple implementations

Tags:

java

guice

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?

like image 685
newbie Avatar asked Nov 08 '11 06:11

newbie


2 Answers

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

like image 84
Andrew McNamee Avatar answered Oct 20 '22 00:10

Andrew McNamee


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;
like image 25
ejboy Avatar answered Oct 20 '22 00:10

ejboy