I’m currently working on Candlepin, a Java web service application that uses Google Guice for dependency injection. I’ve long suspected that I would like Guice. I’m not a big fan of annotations, but I’ll admit that there are something that you can’t do in Java using other approaches.  Guice makes appropriate use of annotations to make dependency injection work in a type safe an intelligent manner.
I had to break a dependency in order to make a class testable. Here’s the old interface:
@Inject public JavascriptEnforcer( DateSource dateSource, RulesCurator rulesCurator, ProductServiceAdapter prodAdapter );
The problem with this is that RulesCurator is a database access class, which means I need a DB for my unit test.  What the JavascriptEnforcer specifically needs is the product of the database query.
Here’s a piece of code from the body of the constructor hat I also want to remove.
ScriptEngineManager mgr = new ScriptEngineManager(); jsEngine = mgr.getEngineByName("JavaScript");
This links us to one creation strategy. I want to use a different one in my Unit test.
My first step was to create a new constructor, and have all of the code I want to extract in the old constructor. This would probably have been sufficient for the unit tests, although it might risk a class not found for the DB stuff. Here’s the new constructor interface:
public JavascriptEnforcer( DateSource dateSource, Reader rulesReader, ProductServiceAdapter prodAdapter, ScriptEngine jsEngine) ;
Here’s where Guice shined. I need two custom compnents here, one which fulfills the rulesReader dependency, the other which fulfils the jEngine. The jsEngine one is easier, and I’ll show that. First, create a custom Provider. A Provider is a factory. For the jsEngine, that factory just looks like this:
package org.fedoraproject.candlepin.guice; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import com.google.inject.Provider; public class ScriptEngineProvider implements Provider<ScriptEngine> { public ScriptEngine get() { return new ScriptEngineManager() .getEngineByName("JavaScript"); } }
Which we then register with our custom module:
class DefaultConfig extends AbstractModule { @Override public void configure() { ... bind(ScriptEngine.class) .toProvider(ScriptEngineProvider.class); } }
Now comes the interesting one. We want a Reader. But a Reader is a very common class, and we don’t want to force everything that needs a Reader to use the same creation strategy. Here is where Guice uses Annoations.
public class RulesReaderProvider implements Provider<Reader> { private RulesCurator rulesCurator; @Inject public RulesReaderProvider(RulesCurator rulesCurator) { super(); this.rulesCurator = rulesCurator; } public Reader get() { return new StringReader(rulesCurator.getRules().getRules()); } }
Note how the Provider itself is a component. This allows us to use another component, the RulesCurator, without creating a direct dependency between the two classes. Still, this does not distinguish one reader from another. That happens with another bind call.
public void configure() { ... bind(ScriptEngine.class) .toProvider(ScriptEngineProvider.class); bind(Reader.class) .annotatedWith(Names.named("RulesReader")) .toProvider(RulesReaderProvider.class); }
Then, the inject Annotation for our Enforcer looks like this:
@Inject public JavascriptEnforcer( DateSource dateSource, @Named("RulesReader") Reader rulesReader, [...] ScriptEngine jsEngine)
The key here is that the @Named matches between the two components.