Griffon Guice Plugin
Having come back from StrangeLoop last week and talking to some our users, I've been thinking a lot potential blockers that might be preventing people from using Griffon in their work applications. One is those is probably dependency injection. Why I chose Guice - I detest XML. I like Guice's modules as a non-XML tag soup way to specify classes to be bound. - Guice's footprint is several magnitudes smaller than Spring. The smallest Guice application requires only 600KB of jar dependencies whereas a comparable Spring application would require several megabytes. Our users are already taking a hit for having to get the groovy-all.jar over the wire. I don't want to add to that pain.
Getting Started
Given an app with the Guice plugin installed(**griffon install-plugin guice**), let's start by creating a couple classes in our src/ directory. Below is a Notifier interface and an implementation:
Notifier.groovy
public interface Notifier {
public void sendMessage(String message);
}
Mail.groovy
public class Mail implements Notifier {
public void sendMessage(String message) {
println "Sending ${message} by Mail"
}
}
As mentioned before, Guice uses Modules instead of XML to specify binding. We can bind our Notifier to the implementation Mail very easily:
GuiceAppModule.groovy
import com.google.inject.*
public class GuiceAppModule extends AbstractModule {
@Override
protected void configure() {
bind(Notifier.class).to(Mail.class);
}
}
Wiring in the Griffon bits
Our plugin does most of the heavy lifting resolving the names of our modules and injecting a Guice injector into the required classes. We just need to give it a few configuration details in griffon-app/conf/Application.groovy. We need to tell Guice where to inject and what modules to inject:
guice {
injectInto = ["controller"]
modules = ["GuiceAppModule"]
}
The last piece is injecting and using our member fields from our controller. In the controller or wherever you deem appropriate, the following will inject the members:
GuiceDemoController.groovy
import com.google.inject.*
class GuiceDemoController {
// these will be injected by Griffon
def model
def view
@Inject Notifier notifier
void mvcGroupInit(Map args) {
// this method is called after model and view are injected
injector.injectMembers(this)
notifier.sendMessage("test");
}
}
When run, the app will print "Sending test by Mail" to the console. The maintainers of Guice caution somewhat against member injection as being less testable. A more traditional constructor-based injection would force Guice to reach below the plugin layer. It's still early days, it might find its way down there anyways.