Search code examples
javadependency-injectionguiceguice-3assisted-inject

Guice - Binding an instance created by assisted injection factory


Let's say that there's class A that's constructor looks something like that:

public A(@Assited long id, @Assisten String name, ServiceA serviceA, ServiceB serviceB)

And there's AFactory:

public interface AFactory{

    A create(long id, String name);
}

So to create an instance of A I obviously need to do something like that:

injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");

BUT, Let's say I have other classes: Class B, Class C and Class D that has a member with type A, for example(with field injection but can be ctor also):

    public class B{
       @Inject
       A a;
    }

And I want that the same instance of A will be injected to those classes. But still have the option to inject another instance of A to other classes (let's say Class E and F).

What is the correct way of doing that? I just can't think of a clean way to do that.


Solution

  • You could structure your module to use Providers (I'm using @Provides methods below, but you can use full Provider classes or instances if you'd like), and mark the consistent A as @Singleton. If you want two bindings of A (consistent and inconsistent), at least one of them should be marked with a binding annotation; I'm using @Named here out of convenience, but you can use any binding annotation as listed in the docs.

    public class AModule extends AbstractModule {
      @Override public void configure() {
        // Install your AFactory module. Here, injections for AFactory should succeed.
        install(new FactoryModuleBuilder().build(AFactory.class));
      }
    
      /**
       * Provides a singleton @Named("consistent") A.
       * Inject @Named("consistent") A into B, C, and D; Guice will cache the instance.
       */
      @Provides @Singleton @Named("consistent")
          A provideConsistentA(AFactory factory) {
        return factory.create(100, "mike");
      }
    
      /**
       * Provides an unscoped A.
       * Inject A without an annotation into E and F; each instance will be separate.
       */
      @Provides @Singleton A provideUnscopedA(AFactory factory) {
        return factory.create(200, "jeff");
      }
    }