32

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?

H3AR7B3A7
  • 4,366
  • 2
  • 14
  • 37
Alex M
  • 395
  • 1
  • 4
  • 6

4 Answers4

29

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
gpampara
  • 11,989
  • 3
  • 27
  • 26
  • Thx! I'll try it for lazy initialization. But is there really no way to inject Injector? – Alex M Feb 01 '10 at 12:13
  • 10
    You can get the injector with `@Inject Injector injector`, can be on the constructor / field / method. – gpampara Feb 02 '10 at 05:37
  • Did you try this? How configure module? Guice restricts binding to core classes: "Binding to core guice framework type is not allowed: Injector." – Alex M Feb 02 '10 at 07:52
  • `@Inject Injector injector` code injects the same `Injector` that used to create instance. So, i suppose, that there is no way to inject other `Injector`. – Alex M Feb 02 '10 at 10:09
  • 2
    @AlexM: Have a look at `childInjectors` if you really need. In general they should not be needed and you should only use a single injector. There are exceptions but they are rare. – gpampara Feb 02 '10 at 10:32
  • 2
    Why do you need multiple Injectors? I really can't imagine. – ColinD Feb 02 '10 at 17:54
  • @Alex M - There's no need to configure an Injector in order for the Injector itself to bounded. By default, every injector know how to inject itself. http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/Injector.html – Itay Maman May 21 '11 at 08:58
15

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.)

Guss
  • 30,470
  • 17
  • 104
  • 128
David Noha
  • 660
  • 5
  • 11
  • 5
    I am not convinced you have understood the rationale behind Guice. It explictly aims to avoid using static fields and state, and you should only very rarely make a direct reference to the Injector itself. You get instances injected by declaring dependencies with @Inject, rather than calling `getInstance()` on the injector. – Tim Gage Mar 17 '12 at 07:42
  • 14
    My only point (which I made rather verbosely) is that you have to start somewhere; it's a chicken-and-egg problem. You can't *only* decorate methods with @Inject and expect anything to happen. Something, somewhere, must call injector.getInstance() or injector.injectMembers() to start it all off. – David Noha Mar 22 '12 at 21:43
  • 1
    What about in a reflection context? Where you do not know the class you want from the context at compile-time? – avanderw Jul 16 '18 at 11:44
  • 3
    It’s not so much “You shouldn’t use `Injector` directly” as much as “You shouldn’t *inject* `Injector`”. Guice provides a lot of checks on Module creation, none of which work if the stuff *inside* the module end up injecting an `Injector` themselves. The initially manually created `Injector` from `Guice.createInjector(...myModules)` is perfectly fine to use. – Paul Féraud Mar 11 '20 at 18:33
8

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.

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • Re: "WHY you want to do that" - For example I want to create dynamic proxies on the fly after bootstrap. my question about this: http://stackoverflow.com/questions/34252268/best-practice-for-creating-dynamic-proxies-with-guice – Daniel Hári Dec 13 '15 at 21:07
  • Another use case: I'm using a third-party library to unmarshal domain objects from storage/network and would like to allow them to require services from the DI graph. – Guss Mar 27 '18 at 15:12
  • 1
    Re: "WHY you want to do that". I'm using Quartz, and in the job I want to call another service --> I must create my own JobFactory. To instance an job I need an Injector. That's the point. – Liem Le Apr 22 '19 at 09:25
3

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.

Drew Stephens
  • 17,207
  • 15
  • 66
  • 82