Atom Feed SITE FEED   ADD TO GOOGLE READER

Guice commands

I recently checked in a new Guice extension called commands. The goal is simple - make it possible to modify your modules at runtime.

But modules aren't naturally data, they're more like code:
    Module module = new AbstractModule() {
protected void configure() {
bind(Soda.class).to(Coke.class);
bind(Snack.class).to(BuffaloRanchDoritos.class);
}
};

How can I convert this executable chunk of code into a manipulatable datastructure? Since Guice is built-on a well-defined API, this wasn't too difficult. I created a custom Binder that recorded the method calls into it made by the modules. I wrapped that in an API that converts the method calls into Command objects:
    CommandRecorder commandRecorder = new CommandRecorder(new FutureInjector());
List<Command> commands = commandRecorder.recordCommands(module);

The Command interface has different implementation for each method* on Binder. There's BindConstantCommand, BindScopeCommand, RequestStaticInjectionCommand and several others. The interface supports visitors, so manipulating commands with type safety is easy.

Finally, there's a class called CommandReplayer that can convert a list of commands back into a module. By extending the template methods, you can rewrite commands while you replay them:
    CommandReplayer rewriter = new CommandReplayer() {
@Override public <T> void replayBind(Binder binder, BindCommand<T> command) {
Key<? extends T> target = command.getTarget().getKey(null);

if (Key.get(Soda.class).equals(target)) {
binder.bind(Soda.class).to(Pepsi.class);
} else {
super.replayBind(binder, command);
}
}
};

Module rewrittenModule = rewriter.createModule(commands);

The last thing left to do is to build an injector from the rewritten module. It works!
    Injector injector = Guice.createInjector(rewrittenModule);
assertEquals(new Pepsi(), injector.getInstance(Soda.class));

We're using commands in a soon-to-be-released test library. I suspect other Guice users will come up with more interesting uses of commands. If you're hacking on Guice, consider using commands when you need to tweak a module.
Update - the "soon-to-be-released" testing library has been released: Guiceberry.