Dependency injection with Groovy and Google Guice

I was looking for a lightweight dependency injection framework to use with Groovy and decided try out Google Guice. In this entry I am exploring version 2.0 without AOP.

This is just a quick overview of Guice and there is probably quite a bit more I haven’t discovered yet. I need to give credit to the guy over at dev.eek.be who has written up a great introductory Guice tutorial.

Creating concrete objects

Guice can implicitly create known concrete objects.

import com.google.inject.*
 
class Greeter {
    String greet() { 'Hello' }
}
 
Injector injector = Guice.createInjector()
Greeter greeter = injector.getInstance(Greeter.class)
 
println greeter.greet() // Prints 'Hello'

Specifying a default implementation

Guice allows you to specify the default implementation of an interface using the @ImplementedBy annotation.

import com.google.inject.*
 
@ImplementedBy(AussieGreeter.class) 
interface Greeter {
    String greet()
}
 
class AussieGreeter implements Greeter {
    String greet() { 'Gudday' }
}
 
class FrenchGreeter implements Greeter {
    String greet() { 'Bonjour' }
}
 
Injector injector = Guice.createInjector()
Greeter greeter = injector.getInstance(Greeter.class)
 
println greeter.greet() // Prints 'Gudday'

Field injection

We can inject the default implementation of an interface into a class using the @ImplementedBy and the @Inject annotations.

import com.google.inject.*
 
@ImplementedBy(AussieGreeter.class) 
interface Greeter {
    String greet()
}
 
class AussieGreeter implements Greeter {
    String greet() { 'Gudday' }
}
 
class FriendlyClock {
 
    @Inject
    private Greeter greeter
 
    String time() {
        greeter.greet() + ', the time is ' + new Date().format('h:mma') 
    }
}
 
Injector injector = Guice.createInjector()
FriendlyClock clock = injector.getInstance(FriendlyClock.class)
 
println clock.time()
// Prints something similar to 'Gudday, the time is 12:34PM'

Constructor injection

We can inject via the constructor by moving the @Inject annotation to the constructor method.

import com.google.inject.*
 
@ImplementedBy(AussieGreeter.class) 
interface Greeter {
    String greet()
}
 
class AussieGreeter implements Greeter {
    String greet() { 'Gudday' }
}
 
class FriendlyClock {
 
    private Greeter greeter
 
    @Inject
    def FriendlyClock(Greeter greeter) {
        this.greeter = greeter
    }
 
    String time() {
        greeter.greet() + ', the time is ' + new Date().format('h:mma') 
    }
}
 
Injector injector = Guice.createInjector()
FriendlyClock clock = injector.getInstance(FriendlyClock.class)
 
println clock.time()
// Prints something similar to 'Gudday, the time is 12:34PM'

Method injection

We move the @Inject annotation to a method for method injection.

import com.google.inject.*
 
@ImplementedBy(AussieGreeter.class) 
interface Greeter {
    String greet()
}
 
class AussieGreeter implements Greeter {
    String greet() { 'Gudday' }
}
 
class FriendlyClock {
 
    private Greeter greeter
 
    @Inject
    def setGreeter(Greeter greeter) {
        this.greeter = greeter
    }
 
    String time() {
        greeter.greet() + ', the time is ' + new Date().format('h:mma') 
    }
}
 
Injector injector = Guice.createInjector()
FriendlyClock clock = injector.getInstance(FriendlyClock.class)
 
println clock.time()
// Prints something similar to 'Gudday, the time is 12:34PM'

Specifying the dependencies using a Module

When you want more dynamic control over which objects are injected we can use a Guice Module to map object interfaces to concrete objects. Here we remove the @ImplementedBy annotation and add a GreeterModule instead.

import com.google.inject.*
 
interface Greeter {
    String greet()
}
 
class AussieGreeter implements Greeter {
    String greet() { 'Gudday' }
}
 
class FrenchGreeter implements Greeter {
    String greet() { 'Bonjour' }
}
 
class FriendlyClock {
 
    @Inject
    private Greeter greeter
 
    String time() {
        greeter.greet() + ', the time is ' + new Date().format('h:mma') 
    }
}
 
class GreeterModule implements Module {
    void configure(Binder binder) {
        binder.bind(Greeter.class).to(FrenchGreeter.class)
    }
}
 
Injector injector = Guice.createInjector(new GreeterModule())
FriendlyClock clock = injector.getInstance(FriendlyClock.class)
 
println clock.time()
// Prints something similar to 'Bonjour, the time is 12:34PM'

Singleton via annotation

An object can be marked as a singleton by using Guice’s @Singleton annotation. Note that the Guice @Singleton annotation conflicts with Groovy’s built-in @Singleton annotation, so we need to use the full path of the annotation class.

First, an example of non-singleton behaviour:

import com.google.inject.*
 
class Greeter {
    String greeting
}
 
injector = Guice.createInjector()
 
greeter = injector.getInstance(Greeter.class)
greeter.greeting = 'Gudday'
println greeter.greeting
greeter = injector.getInstance(Greeter.class)
println greeter.greeting

This prints

Gudday
null

Now we add the @com.google.inject.Singleton annotation

import com.google.inject.*
 
@com.google.inject.Singleton
class Greeter {
    String greeting
}
 
injector = Guice.createInjector()
 
greeter = injector.getInstance(Greeter.class)
greeter.greeting = 'Gudday'
println greeter.greeting
greeter = injector.getInstance(Greeter.class)
println greeter.greeting

This prints

Gudday
Gudday

Singleton via Module

Singletons can also be specified within a Guice Module.

import com.google.inject.*
 
interface Greeter {
    void changeGreeting(greeting)
    String greet(name)
}
 
class AussieGreeter implements Greeter {
    private String greeting = 'Hi';
    void changeGreeting(greeting) { this.greeting = greeting }
    String greet(name) { greeting + ', ' + name }
}
 
class GreeterModule implements Module {
    void configure(Binder binder) {
        binder.bind(Greeter.class).to(AussieGreeter.class).in(Scopes.SINGLETON)
    }
}
 
injector = Guice.createInjector(new GreeterModule())
 
greeter = injector.getInstance(Greeter.class)
greeter.changeGreeting 'Howdy'
println greeter.greet('Groovy')
 
greeter = injector.getInstance(Greeter.class)
println greeter.greet('Groovy')

Which prints

Howdy, Groovy
Howdy, Groovy

It is retaining the set value and is a singleton.

This entry was posted in Groovy and tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

3 Comments

  1. Posted May 18, 2010 at 5:06 pm | Permalink

    Thanks for the credits ;-)

    Nice introduction for Groovy.
    Are you planning to use Guice in your next projects?

  2. Posted May 18, 2010 at 8:12 pm | Permalink

    No problem Wim. Yes, planning to use Guice. It looks like a nice lightweight annotation based DI framwork.

  3. Posted February 4, 2011 at 3:37 am | Permalink

    Comment posted to the groovy mailing list about this entry from Brian Schlining:

    Only thing I might add is to mention the use of the @Named annotation. It’s one way to bind the same interface or class to different implementations. Here’s a contrived example that injects different JPA EntityManagerFactories :

    class FooDaoFactory {
    def entityManagerFactory;

    @Inject
    public FooDaoFactory(@Named(“persist-unit-foo”) EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;

    }
    }

    class BarDaoFactory {
    def entityManagerFactory;

    @Inject
    public BarDaoFactory(@Named(“persist-unit-bar”) EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;

    }
    }

    binder.bind(EntityManagerFactory.class).annotatedWith(Names.named(“persist-unit-foo”)).toInstance(Persistence.createEntityManagerFactory(“fooUnit”));

    binder.bind(EntityManagerFactory.class).annotatedWith(Names.named(“persist-unit-bar”)).toInstance(Persistence.createEntityManagerFactory(“barUnit”));

    def injector = Guice.createInjector()
    def foo = injector.getInstance(FooDaoFactory.class);
    def bar = injector.getInstance(BarDaoFactory.class);