More Than Five
More Than Five

Reputation: 10419

Dynamically Injecting into Google Guice bean

I am using constructor DI with Google Guice.

public class MyClass {

    private MyOtherClass otherclass

    @Inject
    MyClass(MyOtherClass otherClass) {
         this.otherClass = otherClass
    }
}

to get an instance of MyClass, I do:

com.google.inject.Injector.getInstance(MyClass.class)

All good. However, now I have two different versions of MyOtherClass. So I, need something like:

public class MyClass {

    MyInterface myInterface

    @Inject
    MyClass(MyInterface myOtherInterface) {
         this.myOtherInterface = myOtherInterface;
    }
}

}

I need to be able at runtime, instantiate a MyClass with either a MyOtherClassA or MyOtherClassB instance.

So in one code path I need something like:

 com.google.inject.Injector.getInstance(MyClass.class, MyOtherClassA)   // A myClass sinstance which points to MyOtherClassA

and in another code path, I need:

 com.google.inject.Injector.getInstance(MyClass.class, MyOtherClassB)   // A myClass sinstance which points to MyOtherClassB

How do I do this?

Upvotes: 0

Views: 798

Answers (1)

olgacosta
olgacosta

Reputation: 1138

There are two ways to achieve that

  • Binding Annotations

Create the following Annotations class

public class Annotations {
  @BindingAnnotation
  @Target({FIELD, PARAMETER, METHOD})
  @Retention(RUNTIME)
  public @interface ClassA {}

  @BindingAnnotation
  @Target({FIELD, PARAMETER, METHOD})
  @Retention(RUNTIME)
  public @interface ClassB {}
}

Add the bindings in your module class

bind(MyInterface.class).annotatedWith(ClassA.class).toInstance(new MyOtherClassA());
bind(MyInterface.class).annotatedWith(ClassB.class).toInstance(new MyOtherClassB());

To get the necessary instance use this

injector.getInstance(Key.get(MyInterface.class, ClassA.class))
injector.getInstance(Key.get(MyInterface.class, ClassB.class))

MyClass constructor will look like this

@Inject
MyClass(@ClassA MyInterface myOtherInterface) {
   this.myOtherInterface = myOtherInterface;
}
  • @Named

Use the following bindings

bind(MyInterface.class).annotatedWith(Names.named("MyOtherClassA")).toInstance(new MyOtherClassA());
bind(MyInterface.class).annotatedWith(Names.named("MyOtherClassB")).toInstance(new MyOtherClassB());

To get the instance use this

injector.getInstance(Key.get(MyInterface.class, Names.named("MyOtherClassA")))
injector.getInstance(Key.get(MyInterface.class, Names.named("MyOtherClassB")))

MyClass constructor will look like this

@Inject
MyClass(@Named("MyOtherClassA") MyInterface myOtherInterface) {
   this.myOtherInterface = myOtherInterface;
}

Please, refer to Guice documentation for more details.

Upvotes: 2

Related Questions