I have a Java main application with somewhat complex command line arguments. These arguments are currently processed by a CommandLineArgumentProcessor class. Here’s what my code current looks like:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ConfigModule(), new WorkModule(), new ReportModule);
injector.getInstance(I_CommandLineArgumentProcessor.class).processArguments(args);
//Its not until here that I know if I should stub or not with this implementation
...
}
I am now implementing a way to stub out some classes for system testing. To do this I need to swap some of the bindings which Guice uses. Then on the command line I will specify certain flags to turn on/off stubbing of various functionality. However, my problem is that the arguments aren’t processed until after the injector is created.
Do I need to have separate logic to process my stubbing flags prior to creating the injector and then conditionally create the appropriate injector? I’m hesitant on this approach because it divides the logic of processing the command line arguments into two areas of code. Or, is there another (appropriate) way to get Guice to substitute various objects/sub-trees in the object graph after the injector is created? Or do I have one injector for the command line processor and then create another one for the remainder of the modules?
An injector’s bindings are immutable once it’s created (though the bindings themselves can be dynamic). I’d suggest first creating an injector that only binds what you need to do the command line processing. Then do the command line processing, get the flags, and use them when creating another injector that the actual application will use. If there’s stuff you need to bind to be able to do the command line processing that the rest of the application will need as well, you could just create the second injector as a child injector of the first.
There are probably some other weird things you can do, such as having a mutable singleton that the command line flags are set on and using provider methods that depend on that object:
But I think the first approach is much preferable.