Blog

Google Guice and Multibinding

21 Dec, 2009
Xebia Background Header Wave

Last week I started migrating an application that used Spring for DI to Google Guice when I stumbled on multibinding.
Since Google Guice 2.0 we can use Multibinding which allows us to bind multiple objects to a collection.
But the one thing I missed in the current release is the ability to bind objects with a specific annotation. So I thought, why not build it myself 🙂

So lets use the Multibinder example written in the Javadoc of Multibinder.

public class SnacksModule extends AbstractModule {
    protected void configure() {
     Multibinder multibinder = Multibinder.newSetBinder(binder(), ISnack.class);
      multibinder.addBinding().toInstance(new Twix());
      multibinder.addBinding().toProvider(SnickersProvider.class);
      multibinder.addBinding().to(Skittles.class);
    }
  }

With this binding, a Set<ISnack> can now be injected:

  class SnackMachine {
    @Inject
    public SnackMachine(Set snacks) { ... }
  }

This is nice if you have a couple of Snacks, but if you have many and you want your
module clean and simple, you probably want something like this

 multibind(ISnack.class).toAnnotatedClasses(Snack.class);

Where a Snack looks like this:

@Snack
public class Snickers implements ISnack { ... }

To make this possible, I created the following Module:

public abstract class AbstractMultibindModule extends AbstractModule {
    public  AdvancedMultibinder multibind(Class clazz) {
        return new AdvancedMultibinder(clazz);
    }
    public class AdvancedMultibinder {
        private Multibinder multibinder;
        private Class clazz;
        private AdvancedMultibinder(Class clazz) {
            this.clazz = clazz;
            multibinder = Multibinder.newSetBinder(binder(), clazz);
        }
        public Multibinder toAnnotatedClasses(Class bindingAnnotation) {
            return toAnnotatedClasses(bindingAnnotation, clazz.getPackage().getName());
        }
        public Multibinder toAnnotatedClasses(Class bindingAnnotation, String basePackageName) {
            for (Class clazz : AnnotationUtil.getAnnotatedClasses(bindingAnnotation, basePackageName)) {
                multibinder.addBinding().to(clazz);
            }
            return multibinder;
        }
        public LinkedBindingBuilder addBinding() {
            return multibinder.addBinding();
        }
    }
}

As you can see the multibind method returns an AdvancedMultibinder. We cannot extend Multibinder because it has a private Constructor, so instead I use the multibinder internally and call methods on it to add bindings.
The AdvancedMultibinder has a method toAnnotatedClasses, which takes the annotation class as a parameter and adds a binding for each annotated class.
Now we can do the following.

     AdvancedMultibinder multibinder = multibind(ISnack.class);
     multibinder.toAnnotatedClasses(Snack.class);
     // Add a non annotated class to the bind.
     multibinder.addBinding().to(Skittles.class);
     bind(Machine.class).to(SnackMachine.class);

I have attached the example project here so you can look into the code yourself.

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts