@Inject Injector is injecting root injector rather than child injector

2,301 views
Skip to first unread message

Michael Burton

unread,
Aug 14, 2009, 8:11:42 PM8/14/09
to google-guice
I have a class that requires an Injector to do some work (it needs to
construct some objects on the fly and then injectMembers for them).

class DoSomething {
@Inject protected Injector injector;

public void doIt() {
...
injector.injectMembers(stuff);
...
}
}


In my application, I have two levels of injector. I have a master
injector, created using Guice.createInjector(), and I have a few child
injectors, created by calling master.createChildInjector(). I've
verified that DoSomething was created using a binding in one of the
child injectors.

The weird thing is that if I inspect DoSomething.injector, I find that
it is the MASTER injector, not the CHILD injector. I would have
expected the Injector to be the child injector since it was the child
that instantiated DoSomething.

This seems to be causing me problems like the following:

E/AndroidRuntime( 1515): com.google.inject.ConfigurationException:
Guice configuration errors:
E/AndroidRuntime( 1515):
E/AndroidRuntime( 1515): 1) A binding to
com.google.inject.Provider<android.app.Activity> already exists on a
child injector.
E/AndroidRuntime( 1515): while locating
com.google.inject.Provider<android.app.Activity>
E/AndroidRuntime( 1515): for field at
com.XXX.http.BaseHttpGet.activityProvider(Unknown Source)
E/AndroidRuntime( 1515): while locating com.XXX.model.ImageUtils
$GetImage
E/AndroidRuntime( 1515):
E/AndroidRuntime( 1515): 2) A binding to com.XXX.http.Http already
exists on a child injector.
E/AndroidRuntime( 1515): while locating com.XXX.http.Http
E/AndroidRuntime( 1515): for field at com.XXX.http.BaseHttpGet.http
(Unknown Source)
E/AndroidRuntime( 1515): while locating com.XXX.model.ImageUtils
$GetImage
E/AndroidRuntime( 1515):

My interpretation of that error is that when I call
injector.injectMembers(), the master injector attempts to generate a
few bindings that it can't find, but errors out because those bindings
already exist in the child injector.

Is there a way I can tell Guice to inject the "correct" Injector
instead of always the root injector? Or alternately, is there a way I
can get the correct injector manually somehow?

Cheers,
Mike

Dhanji R. Prasanna

unread,
Aug 15, 2009, 5:55:00 AM8/15/09
to google...@googlegroups.com
The easy answer is to simply bind the child injector using a provider.

Dhanji.

Dan Godfrey

unread,
Aug 20, 2009, 8:22:13 AM8/20/09
to google-guice
Could you elaborate further, we've hit exactly the same issue and
can't get around it.

Thanks,
Dan.


On Aug 15, 10:55 am, "Dhanji R. Prasanna" <dha...@gmail.com> wrote:
> The easy answer is to simply bind the child injector using a provider.
> Dhanji.
>

Michael Burton

unread,
Aug 20, 2009, 12:26:20 PM8/20/09
to google...@googlegroups.com
Hi Dan,

Thanks for repying, I've been meaning to follow up on this thread.

I had originally done some trickery to bind DoSomething to the child
injector, and after I made my first post it became clear to me that
that might not have worked the way I expected.

I changed my module to be more specific by simply saying
"bind(DoSomething.class);" in the child (no to() statement or
anything), and that solved my problem. References to the Injector in
objects instantiated by the child subsequently referred to the child
rather than parent injector. It may or may not solve the problem for
you.

I believe the solution that Dhanji is proposing probably would have
worked as well. You could
bind
(Injector
.class
).annotatedWith
(Names.named("child").toProvider(ChildInjectorProvider.class), then
create a ChildInjectorProvider class whose get method returns the
child injector.

I imagine that you'd have to annotate the binding like I did above
(since Injector is automatically bound) but I don't know for sure as I
haven't tried this directly.

Mike

Stuart McCulloch

unread,
Jun 21, 2012, 8:58:46 PM6/21/12
to google...@googlegroups.com
On 22 Jun 2012, at 01:30, TonyD wrote:
I know this chain is old, but I haven't seen another (more recent) posting that talks about this. I'm still confused about this. Basically, I'd like to inject the child injector as well. I have a case where I cannot use the FactoryModuleBuilder and would like to pass the child injector. I run into the same problem where the injector is actually the root when I was expecting the child.

I will provide some sample code below, but if someone could give a full example of the provider solution above, I would be much obliged. When I try to make the provider solution work, I get an error from Guice saying I basically have no right to try to inject the Injector class, even using the "Names.named()" approach.

// The interface of what I want to inject
public interface IDriver
{

}

// Implementation of what I want to inject
public class Driver implements IDriver
{
    private final Injector injector;

    @Inject
    public Driver(Injector injector)
    {
        this.injector = injector;
       
        System.out.println("Driver injector: '" + this.injector.hashCode() + "'.");
    }   
}

// Parent module
public class ParentModule extends AbstractModule
{
    @Override
    protected void configure()
    {
    }
}

// Child module
public class ChildModule extends AbstractModule
{
    @Override
    protected void configure()
    {
        bind(IDriver.class).to(Driver.class).in(Singleton.class);

^ try adding an explicit binding here for the concrete class, ie.  bind(Driver.class);

Summary of what (I think) is going on: the child injector gets a request for an instance of IDriver.class and it finds the binding which leads to Driver.class.
The child injector now needs an instance of Driver.class, so it looks for a local binding for Driver.class - it can't find one so it consults the parent injector,
as you could have bound Driver.class to something else in the parent. There's no explicit binding for Driver.class in the parent so it creates a just-in-time
binding for Driver.class - this implicit binding is added to the parent which is then why the injector being injected is the parent. By adding an explicit binding
for Driver.class you stop the child injector from consulting its parent and you should then see the child injector being injected.


this will then give you early warning about any missing/implicit bindings so you can make them explicit (can be useful when you need to work with child injectors).

HTH

    }
}

//Entry point/program
public class RunTestChildInjector
{
    public static void main(String[] args)
    {
        Injector parent = Guice.createInjector(new ParentModule());
        System.out.println("Parent injector: '" + parent.hashCode() + "'.");
       
        Injector child = parent.createChildInjector(new ChildModule());
        System.out.println("Child injector: '" + child.hashCode() + "'.");
       
        child.getInstance(IDriver.class);
    }
}

// Results:
Parent injector: '1592418026'.
Child injector: '1582325328'.
Driver injector: '1592418026'.

// Expected:
Child injector = Driver injector


Why do I want the injector to be the child?
- Basically because I have a situation where I want multiple instances of driver to exist, and have all other objects created by the child injector (not shown) to be associated with that driver
- The objects would also interact with "global" objects created by the parent module
- Of course, most are built automatically by Guice, but there are some where I want/need to use the Injector

So...
- To me it made intuitive sense that the injector used for the driver should have been the child injector, but I get a similar error as noted in the first post (Unable to create binding for ...It was already configured on one or more child injectors or private modules) when I try to take the injector in driver and get an instance of another object defined in the child module (not shown)
- When I checked the javadoc for createChildInjector I read "No key may be bound by both an injector and one of its ancestors. This includes just-in-time bindings. The lone exception is the key for Injector.class, which is bound by each injector to itself."  This tells me that the injector would have the updated child key as the only exception, so I thought what I had above should have worked.

Basically, if this is as-designed, I'm looking for a full example of how to get and use the child injector inside the Driver object.

Any help is greatly appreciated.



--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/it5I-HuBP-wJ.
To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.

Message has been deleted

Kevin Brightwell

unread,
Mar 26, 2014, 1:52:27 PM3/26/14
to google...@googlegroups.com
Hello,

Firstly, I work with TonyD on the same project and ran into the same problems in a different area.

In our code base, we have something similar to, but more accurately:

public class Driver implements IDriver
{
    private final Injector injector;

    @Inject
    public Driver(Injector injector)
    {
        this.injector = injector;
      
        System.out.println("Driver injector: '" + this.injector.hashCode() + "'.");
    }  
   
    public IFoo createFoo() {
        return this.injector.getInstance(IFoo.class);
    }
   
    public IBar createBar() {
        return this.injector.getInstance(IBar.class);
    }
}


From this extended example, we were getting instances using the injected Injector instance.

From working on different code, I needed to produce Provider<> instances due to lifetime requirements. I replaced the Injector injection using Provider<>s for each type created, that is:

public class Driver implements IDriver
{
    private final Provider<IFoo> pFoo;
    private final Provider<IBar> pBar;

    @Inject
    public Driver(Provider<IFoo> pFoo, Provider<IBar> pBar)
    {
        this.pFoo = pFoo;
        this.pBar = pBar;
    }  
   
    public IFoo createFoo() {
        return this.pFoo.get();
    }
   
    public IBar createBar() {
        return this.pBar.get();
    }
}


With this addition and removal of the extra bind() statements, the code became more verbose, but also more concise. It also removed the additional binds and removes a possibly concerning injection issue.

This is a bit of a design philosophy problem we had in our code base which was to avoid Provider<> because we were under the assumption that you have to creat your own -- Guice implements these for us under the covers.

I hope that others who come across this can benefit from our solution.

Cheers,

Kevin

On Thursday, 21 June 2012 23:38:23 UTC-4, TonyD wrote:
Hi Stuart,

Thank you! That makes sense. I added the bind(<implementing class>) below each bind in the child module and sure enough it worked.

I will look into adding the explicit bindings check as well, as I'd rather fail fast than get surprised later.

I guess what really threw me off was when I was debugging (as shown above), I was getting the parent injector object in Driver when I was expecting the child injector. I still don't quite get why, but at this point, I'm just happy it works.

Thanks again!
Reply all
Reply to author
Forward
0 new messages