Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting Collection of Classes with Guice

Tags:

java

guice

I'm trying to inject things with Google Guice 2.0 and I have the following structure:

FooAction implements Action BarAction implements Action 

I then have an ActionLibrary with the following constructor:

ActionLibrary (List<Action> theActions) 

When I request an instance of ActionLibrary from Guice, I would like Guice to identify both of the registered Action classes (FooAction, BarAction) and pass them into the constructor. The motivation here being that when I add a third action BazAction, it would be as simple as registering it in the Module and it would automatically be added to the list in the constructor.

Is this possible?

like image 446
Scruffers Avatar asked Dec 10 '10 16:12

Scruffers


People also ask

How do you inject a Guice class?

Client Application We need to create Injector object using Guice class createInjector() method where we pass our injector class implementation object. Then we use injector to initialize our consumer class. If we run above class, it will produce following output.

What does @inject do in Guice?

Note that the only Guice-specific code in the above is the @Inject annotation. This annotation marks an injection point. Guice will attempt to reconcile the dependencies implied by the annotated constructor, method, or field.

What is @inject annotation in Guice?

@Target(value={METHOD,CONSTRUCTOR,FIELD}) @Retention(value=RUNTIME) @Documented public @interface Inject. Annotates members of your implementation class (constructors, methods and fields) into which the Injector should inject values. The Injector fulfills injection requests for: Every instance it constructs.

Is Guice lazy?

When does guice make the dependencies available? In general, construction is lazy (for non-singleton classes, this is intuitive - you don't know you need a new instance until someone tells you to inject one somewhere). The exception is for eager singletons which are constructed (wait for it) eagerly.


2 Answers

What you want for this is Multibindings. Specifically, you want to bind a Set<Action> (not a List, but a Set is probably what you really want anyway) like this:

Multibinder<Action> actionBinder = Multibinder.newSetBinder(binder(), Action.class); actionBinder.addBinding().to(FooAction.class); actionBinder.addBinding().to(BarAction.class); 

Then you can @Inject the Set<Action> anywhere.

like image 163
ColinD Avatar answered Sep 16 '22 11:09

ColinD


Let me show you what I consider an even better way of multibinding things. If you want Actions to be pluggable and let anyone add them, it's often useful to provide a simple Module for someone to use that hides needing to instantiate the Multibinder. Here's an example:

public abstract class ActionModule extends AbstractModule {   private Multibinder<Action> actionBinder;    @Override protected void configure() {     actionBinder = Multibinder.newSetBinder(binder(), Action.class);     configureActions();   }    /**    * Override this method to call {@link #bindAction}.    */   protected abstract void configureActions();    protected final LinkedBindingBuilder<Action> bindAction() {     return actionBinder.addBinding();   } } 

Now why is this better? It allows someone to use an ActionModule from anywhere to add more Actions via the standard binding API. I think it's more readable. Here's an example usage:

public final class MyStandardActionModule extends ActionModule() {   @Override protected void configureActions() {     bindAction().to(FooAction.class);     bindAction().to(BarAction.class);     // If you need to instantiate an action through a Provider, do this.     bindAction().toProvider(BazActionProvider.class);     // You can also scope stuff:     bindAction().to(MySingletonAction.class).in(Singleton.class);   } } 

This pattern of using a Module to hide the multibinder is used in Guice code. It's a little work up front, but keeps things clean. You can also do something similar for a MapBinder if you need to. Keep in mind you can instantiate as many ActionModules as you want.

like image 44
Tom Avatar answered Sep 20 '22 11:09

Tom