views:

42

answers:

2

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?

+2  A: 

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:

@Provides
protected Foo provideFoo(Config config) {
  return config.isStubFoo() ? new StubFoo() : new RealFoo();
}

But I think the first approach is much preferable.

ColinD
Thanks Colin. The first approach of multiple injectors has grown on me and I think this will be the one that I use. As a newbie to Guice, I've got enough 'weird things' to deal with, so I'll keep it simple for now! But I think I understand you're provider example.
Chris Knight
+1  A: 

Hi Chris,

Have you considering using child injectors? From your example, it looks like your only need for the root inject is to get an instance of I_CommandLineArgumentProcessor. Without more context i would suggest specifying your root injector with the minimum bindings required to make a I_CommandLineArgumentProcessor.

Then you can use your I_CommandLineArgumentProcessor in conjunction with some other injected provider-like class to give you back the modules to use that you pass to the createChildInjector method.

alpian
Thanks alpian, I hadn't heard of child injectors before but now that I've read the API I think I understand what they do. Because I don't require the I_CommandLineArgumentProcessor beyond the initial call, I think I'll stick with creating a new injector as being the cleanest solution for me. But thanks for teaching me something new :)
Chris Knight