Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice injector.getInstance() - good practice?

Let's say I have two applications sharing the same library. This library contains common classes like DAOs, Utils, etc. Everything in the shared library is wired with Guice. My two apps depend on this library but do not have a direct dependency on Guice.

 ______    ______    ______
|      |  |      |  |      |
| APP1 |->| LIB  |<-| APP2 |
'------'  '------'  '------'

I currently use something like this:

static <T> Utils.getInstanceOf (Class<T> type);

which is simply a wrapper for:

injector.getInstance (Class<T> type);

But the guice docs say:

When feasible, avoid using this method, in favor of having Guice inject your dependencies ahead of time.

So what's the best way to provide dependency injection for the two apps without having to manually bind them in a Guice module?

like image 550
albogdano Avatar asked Oct 11 '13 06:10

albogdano


3 Answers

So what's the best way to provide dependency injection for the two apps without having to manually bind them in a Guice module?

There is no such way. You either embrace Guice totally or do not use it and pass your dependencies explicitly. Well, structuring your code in such way so you never directly create class dependencies, passing them instead through a constructor, also may be called 'dependency injection', but I'm sure this is not what you meant. If you do not want to use Guice in your apps, you won't be able to get anything better than getInstance(), which is ugly, especially because you're using static wrapper.

Ideally your library should provide a module which you can install via Guice.createInjector() in your applications, or, in the other way around, the library should provide an Injector instance which you can use in your applications by using createChildInjector() and providing application-specific modules. Slight modification of this approach is passing application-specific modules to the library so they will be used to create Injector. I have recently written Guice-based API over custom servlet-like interface which didn't support any kind of DI at all using the last approach, and it is working perfectly.

It is not at all hard to use Guice in servlet or Jersey environment. The latter, for example, has out-of-the-box integration with Guice (at least, in 1.x versions). Guice servlet extension is also very good and convenient. Just try it and see for yourself.

like image 54
Vladimir Matveev Avatar answered Nov 18 '22 20:11

Vladimir Matveev


static <T> Utils.getInstanceOf (Class<T> type);

What you have ended up with is a Service Locator.

While in a few small cases this it is acceptable for the injector to escape into other creational objects, I don't think this one of them. You have ended up with all the disadvantages of a Service Locator and all the advantages can be had by using the tool you are already using.

like image 5
Michael Lloyd Lee mlk Avatar answered Nov 18 '22 20:11

Michael Lloyd Lee mlk


If you have a method that needs to create a new instance of class C at runtime, bind a Provider to your class. C would be bound in the usual way, e.g.

public CModule extends AbstractModule {
    @Overide
    public void configure() {
        bind(C.class).to(CImpl.class);
    }
}

The class that creates C instances would look like this:

class UserOfC {
    private Provider<C> cProvider;
    ...

    @Inject
    UserOfC(Provider<C> cProvider, ...) {
        this.cProvider = cProvider;
        ...
    }

    public void doSomethingWithAC (...) {
        C myC = cProvider.get();  // not a singleton; new instance created!
        ...
    }
}

Guice supportes Provider injection free for nothing. If C is bound, you can inject a Provider as easily as you can inject an instance of C.

Additional Suggestions:

I strongly recommend that you inject all dependencies at construction, if at all possible, even if it requires writing a few more lines of code. I've used Guice for years, and have yet to need partial construction or any other advanced feature.

When I am faced with the need for partial injection, I generally write my own factory. I find it much easier to understand and debug when I write the code.

like image 5
Eric Mintz Avatar answered Nov 18 '22 20:11

Eric Mintz