James Williams
LinkedInMastodonGithub

Griffon Guice Plugin

Tags: Griffon

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.