40

I am extending Guice's AbstractModule and inside of the extending class I need access to Guice's injector. It that possible, if yes, how?

CraigTeegarden
  • 8,173
  • 8
  • 38
  • 43
stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270

2 Answers2

64

This is an unusual request. Modules are more like config files than logic files: The Module is read to create the Injector, and then as soon as the Injector is created the module has done its job. For a simple Module, the Injector literally doesn't exist until the Module is ready to be discarded.

In any case, rather than requesting an Injector to get class X, you should typically request a Provider<X>. Guice will inject an X or Provider<X> for any binding of X, Provider<X>, or @Provides X, so you can almost always do this instead. That said, injecting the Injector will allow you to get an instance reflectively, or to inspect the Injector's bindings (etc).

Here are a few valid reasons/designs that would require accessing an Injector from within a Module:

In a @Provides method:

Modules can contain mini-providers in methods annotated with @Provides. Remember that Injector is injectable: If you need an Injector in one of those methods, you can just accept it as a parameter:

public class OneModule extends AbstractModule {
  @Override public void configure() { /* ... */ }

  @Provides YourDependency getYourDependency(Injector injector) {
    return injector.getInstance(Class.forName(yourDependencyName));
  }

  @Provides Something getSomething(SomethingImpl something) {
    return initialize(something); // preferred: only ask for what you need
  }

  @Provides SomethingElse getSomethingElse(Provider<Thing> thingProvider) {
    return new SomethingElse(thingProvider); // asking for a provider works too
  }
}

To get a Provider in your configure():

AbstractModules expose getProvider() for exactly this reason, though you'll get an error if you call get() on that Provider before the injector is ready to provide it (such as at configuration time):

public class TwoModule extends AbstractModule {
  @Override public void configure() {
    bind(Thingy.class).toInstance(
        new MyThingy(8675309, getProvider(Another.class)));
  }
}

You can probably call getProvider(Injector.class) but I don't know whether that works and I don't know why you'd want to.

To get an instance in your configure():

This is a bad idea; Guice is not ready to provide instances until after all of the configure methods run. The closest you can get is to create a child Injector using the other modules and pass it into this module, but even that is rarely needed.

public class MainClass {
  public static void main(String[] args) {
    Injector firstStage =
        Guice.createInjector(new OtherModule1(), new OtherModule2());
    // An alternative design would @Inject-annotate fields in ThreeModule
    // and get it from firstStage, but that's nonstandard and may be confusing.
    Injector secondStage =
        firstStage.createChildInjector(new ThreeModule(firstStage));
  }
}

public class ThreeModule extends AbstractModule {
  private final Injector otherInjector;

  public ThreeModule(Injector otherInjector) { 
    this.otherInjector = otherInjector;
  }

  @Override public void configure() {
    bindStuffBasedOn(otherInjector);
  }
}
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • 2
    I agree, it's an unusual request and might hint at a design smell. – ilikeorangutans Apr 15 '13 at 17:48
  • the getProvider() method in AbstractModule#configure() is the way to go – leozilla Feb 16 '17 at 08:38
  • 11
    @ilikeorangutans love such comments; they always leave me with feeling that my design smells, but without any idea how to improve it :D – Line Jan 16 '18 at 07:15
  • 1
    Though unusual, I don't think it's always a bad design, haha. We have a scenario, where we want to dynamically get an instance from its class. As you approach dynamic scenarios (reflection and such) you start needing advanced "meta" features. – Ferran Maylinch Jul 09 '20 at 08:38
  • @FerranMaylinch To speak for myself: my objection has nothing to do with accessing or using an Injector dynamically. Of course it makes sense to be clear about your dependencies when possible, and to minimize the use of Guice-specific components where possible, but reflective access via Injector is an excellent use case for Guice. My advice is more about clearly differentiating "configure-time" from "run-time": Your use of Injector should be in classes instead of Modules (with the possible exception of `@Provides` methods), because the Injector won't be ready until after `configure` is run. – Jeff Bowman Jul 21 '20 at 17:41
2

You can inject the Injector in your class or provider, but it should be used sparsely.

I found it here: https://groups.google.com/d/msg/google-guice/EiMDuDGei1Q/glxFhHKHHjsJ

See also: https://github.com/google/guice/wiki/InjectingTheInjector

public class MyClass
{
    @Inject
    public MyClass(Injector injector) { ... }
}

public class MyModule extends AbstractModule {
    ...

    @Provides
    public Something provideSomething(Injector injector) { ... }

}
Ferran Maylinch
  • 10,919
  • 16
  • 85
  • 100