Google Guice AssistedInject example in Groovy

If you are using Google Guice to manage your object dependencies then you may find a situation where you have a constructor that has parameters required from Guice and some parameters from the calling code.

For example, suppose you are creating a Book which requires a BookService and a name when it is created:

class Book {
    Book(BookService bookService, String name) {
        ...
    }
}

In this case we want the BookService to be injected by Guice, but the name to be supplied by the calling code.

Guice provides something called an AssistedAnnotation that can help in this situation.

First, for assisted annotations to work you will need the following jars (which are all available within the downloads at the Guice download site):

  • Either guice-2.0-no_aop.jar or guice-2.0.jar
  • guice-assistedinject-2.0.jar
  • aopalliance.jar

Let’s take a look at some example code.

AssistedInject with different parameter types

import com.google.inject.*
import com.google.inject.assistedinject.*
 
// Our BookService will be injected into our Book below
class BookService {
	def read(Book b) {
		'Reading ' + b.name
	}
}
 
// Create an interface for a factory that will create our books.
// Guice will generate an implementation of this for us.
interface BookFactory {
	Book create(String name)
}
 
// Create out Book
class Book {
 
    private BookService bookService
    String name
 
    // Annotate the constructor with @Inject
    // and annotate the extra variable we need to pass in with @Assisted
    @Inject
    Book(
            BookService bookService,
            @Assisted String name
        ) {
        this.bookService = bookService
        this.name = name
    }
 
    String read() {
        bookService.read(this)
    }
}
 
// Create the Guice Module that enables our
// BookFactory implementation to be generated
// (i.e. some magic happens here) 
class BookModule implements Module {
    void configure(Binder binder) {
    	binder.bind(BookFactory.class).toProvider(
                FactoryProvider.newFactory(BookFactory.class, Book.class)
            )
    }
}
 
// Create our Guice injectory
injector = Guice.createInjector(new BookModule())
 
// Get the factory that was created by Guice for us
bookFactory = injector.getInstance(BookFactory.class)
 
// Test that is creates a book correctly for us
Book book = bookFactory.create('Head First Guice')
 
// This prints 'Reading Head First Guice'
println book.read()

AssistedInject with the same parameter types

If some of our parameters are of the same type, then we need to distinguish between then with some additional modified annotations.

Let’s add an author to our Book constructor, which is also a String.

import com.google.inject.*
import com.google.inject.assistedinject.*
 
class BookService {
    def read(Book b) {
        'Reading ' + b.name + ' by ' + b.author
    }
}
 
interface BookFactory {
    // Add some named annotations here
    Book create(
            @Assisted('name') String name,
            @Assisted('author') String author
        )
}
 
class Book {
 
    private BookService bookService
    String name
    String author
 
    // And add the corresponding named annotations here
    @Inject
    Book(
            BookService bookService,
            @Assisted('name') String name,
            @Assisted('author') String author
        ) {
        this.bookService = bookService
        this.name = name
        this.author = author
    }
 
    String read() {
        bookService.read(this)
    }
}
 
class BookModule implements Module {
    void configure(Binder binder) {
    	binder.bind(BookFactory.class).toProvider(
                FactoryProvider.newFactory(BookFactory.class, Book.class)
            )
    }
}
 
injector = Guice.createInjector(new BookModule())
bookFactory = injector.getInstance(BookFactory.class)
 
Book book = bookFactory.create('Head First Guice','Google')
println book.read()
 
// Which prints 'Reading Head First Guice by Google'
This entry was posted in Groovy and tagged , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.