1

I have a Module that uses a flag to decide whether or not to install another module. Is there a way to achive that by injection, or do I need to explicitly pass the flag's value in the ctor?

 public class MyModule implements Module {

    private final Boolean shouldInstallOtherModule;

    @Inject public MyModule(Boolean shouldInstallOtherModule) {
        this.shouldInstallOtherModule = shouldInstallOtherModule;
    }

    public void configure() {
      if(shouldInstallOtherModule) {
       install(SomeOtherModule);       
       }

    }
}
user844541
  • 2,868
  • 5
  • 32
  • 60
  • Do you really need it? Seems such a weird requirement... Guice modules are configuration files, even if written in a programming language: you shouldn't use conditionals and loops. What are your *true* requirements? – Raffaele May 05 '15 at 11:19

2 Answers2

2

Though it is possible to inject into a Module, or to get a Module from an Injector, it's a much better design decision not to: Modules can access their own injectors in limited ways, so having @Inject methods and fields on a Module introduces a second Injector and that could become confusing very quickly.

In this situation, I would create an Injector for the configuration alone, then create a child injector with Modules based on that configuration. Your Module should be responsible for configuring bindings, not choosing which other Modules to install—that's a job better left for the root application.

If you feel you must keep the conditional installation in a Module, just take the configuration value directly as a constructor parameter and let your top-level object (that creates your injector) provide it however it needs. This will prevent two Injectors from being active in the same object instance at the same time, which makes everything easier to understand.

For similar problems and solutions, see this SO question: "Accessing Guice injector in its Module?"

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • To add a bit to what Jeff said: I have used the method of creating child injectors and it appears to work well. Conceptually, you have a "bootstrap" injector that gets the application up and running and then a second child injector to create the object graph based on user input. He is right though in that it can get confusing with too many injectors lying around. One other approach to consider would be to see if @Provides or Assisted Injection can help solve your problem. – chooks May 06 '15 at 11:02
0

Well, I would suggest you to have a look at Netflix Governator framework. The configuration would look like this:

LifecycleInjector injector = LifecycleInjector.builder()
          .withModuleClass(MyModule.class)
          .withBootstrapModule(new InitializationModule()).build();

where InitializationModule:

public class InitializationModule implements BootstrapModule {

    public void configure() {
      bind(Boolean.class).toInstance(readFromConfig());
    }
}

Or better you can use Configuration feature

which would look like this

 public class MyModule implements Module {
    //read from config.properties
    @Configuration("configs.shouldInstallOtherModule")
    private final Boolean shouldInstallOtherModule;

    public void configure() {
      if(shouldInstallOtherModule) {
       install(SomeOtherModule);       
       }

    }
}
Milan Baran
  • 4,133
  • 2
  • 32
  • 49