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.
Written by
Mischa Dasberg
Our Ideas
Explore More Blogs

Where the GitHub Copilot Extension Points Break Governance
A lot of the recent additions to the GitHub Copilot ecosystem add real value for individual developers, yet they also expand the security surface that...
Rob Bos
Contact


