views:

34

answers:

3

There's something I just don't get about guice: According to what I've read so far, I'm supposed to use the Injector only in my bootstrapping class (in a standalone application this would typically be in the main() method), like in the example below (taken from the guice documentation):

public static void main(String[] args) {
    /*
     * Guice.createInjector() takes your Modules, and returns a new Injector
     * instance. Most applications will call this method exactly once, in their
     * main() method.
     */
    Injector injector = Guice.createInjector(new BillingModule());

    /*
     * Now that we've got the injector, we can build objects.
     */
    RealBillingService billingService = injector.getInstance(RealBillingService.class);
    ...
  }

But what if not all Objects I ever need can be created during startup? Maybe I want to respond to some user interaction when the application is running? Don't I have to keep my injector around somewhere (e.g. as a static variable) and then call injector.getInstance(SomeInterface.class) when I need to create a new object?

Of course spreading calls to Injector.getInstance() all over the place seems not to be desirable.

What am I getting wrong here?

+2  A: 

Yes, you basically only should use the Injector to create get the instance for the root-object. The rest of the application shouldn't touch the Guice-Container. As you've noticed, you still need to create some objects when required. There are different approaches for doing that, each suitable for different needs.

Inject a Provider Provider is a interface from Guice. It allows you to request a new instance of a object. That object will be created using Guice. For example.

 class MyService{
     private Provider<Transaction> transactionProvider;
     public MainGui(Provider<Transaction> transactionProvider){
         this.transactionProvider = transactionProvider;
     }

     public void actionStarted(){
         Transaction transaction = transactionProvider.get();
     }

Build a Factory Often you need some kind of factory. This factory uses some injected services and some parameters and creates a new object for you. Then you use this factory for new instances. Then you inject that factory and use it. There also help for this with the AssistedInject-extension

I think with these two possibilities you rarely need to use the Guice-Injector itself. However sometimes is still appropriate to use the injector itself. Then you can inject the Injector to a component.

Gamlor
+1  A: 

To extend on the answer Gamlor posted, you need to also differentiate between the object types you are using.

For services, injection is the correct solution, however, don't try to always make data objects (which are generally the leafs in your object graph) injectable. There may be situations where that is the correct solution, but injecting a Provider<List> is probably not a good idea. A colleague of mine ended up do that, it made the code base very confusing after a while. We just finished cleaning it all out and the Guice modules are much more specific now.

gpampara
Yes, I completely agree with that.
Gamlor
A: 

In the abstract, I think the general idea is that if responding to user events is part of the capabilities of your application, then, well...

BillingService billingService = injector.getInstance(BillingService.class);
billingService.respondToUserEvent( event );

I guess that might be a little abstract, but the basic idea is that you get from Guice your top-level application class. Judging from your question, I guess that maybe BillingService isn't your top-level class?

Darren Gilroy