Reputation: 395
Situation: i need lazy dependency instantiation in some FooClass
, so i pass Injector
to class as a constructor parameter.
private final Injector m_injector;
public FooClass(@Named("FooInjector") Injector injector) {
m_injector = injector;
}
But guice doesn't permit to bind core classes (injectors, modules and etc). What is the solution?
Upvotes: 32
Views: 25834
Reputation: 670
As others have already answered, you can simply use @Inject Injector
because Guice defines the binding itself.
Normally you only need one Injector
in your app, and a static variable is an even easier way to store and access a singleton than injecting it. In our web app, we use stripes-guicer and get the Injector
from its static method GuiceInjectorFactory.getInjector()
when we need it (in our Hibernate interceptor, for example).
I'm a little baffled by the advice that "you shouldn't use Injector directly." How else would I get an instance injected except by calling injector.getInstance()
or injector.injectMembers()
? There is no way. Yes, you can define Provider methods, but they will never be called unless somewhere, something uses an Injector. Yes, there are modules that use the Injector
for you like the ServletModule; you have to create the Injector
yourself, but you can leave it to the ServletModule
after that.
So in some circumstances, you can avoid using the Injector
directly, but that doesn't mean you "shouldn't" use it. If you're using Guice alone without any optional modules, then you "should" be using an Injector
all over the place because there's no other way to trigger injection. (I think developers who spend all day writing code inside frameworks sometimes forget that some people actually instantiate their own objects.)
Upvotes: 15
Reputation: 17827
The arguments that you probably shouldn't be injecting an instance of Injector
are quite valid, but as with any rule there are exceptions.
I have a factory class that takes in class references for which it needs to provide an instance. The instances aren't necessarily known (really, they are, but there are a lot and there might be more) so I can't make Providers for all of them.
public class ThingFactory {
private Injector injector;
@Inject
ThingFactory(Injector injector) {
this.injector = injector;
}
public <T> T getInstance(Class<T> aClass) {
return injector.getInstance(aClass);
}
}
The real class in my app is extending and overriding another class—that's why this class is basically a passthrough to Guice.
Upvotes: 3
Reputation: 110054
As @gpampara said, Provider<T>
should be used for lazy/optional initialization. Also, as I said in my answer to your other question, you should be avoiding references to the Injector
in your code in almost all cases.
That said, in a class that is created by Guice, the Injector
that is creating the object can be injected just by declaring a dependency on Injector
. The Injector
is automatically available for injection without you declaring any binding for it.
If you do inject the Injector
, you should think about WHY you want to do that. Why don't you just declare dependencies on the actual interfaces/classes the class depends on? It's just as easy to add a new dependency to the constructor as it is to retrieve an instance of some dependency through the Injector
elsewhere in your code, and it makes the code far more understandable as well.
Upvotes: 8
Reputation: 12049
You should not be using the Injector
directly. Rather pass in the Provider<FooClass>
instead. Also, you should be injecting the provider in the places where you use FooClass
.
private final Provider<FooClass> provider;
@Inject
public ClassWhereFooIsUsed(Provider<FooClass> provider) {
this.provider = provider;
}
.... somewhere else
FooClass f = provider.get(); // This is lazy
Upvotes: 29