Hello,

Foreword, I work with TonyD on the same project, so I ended up finding his 
code and running into a similar problem in separate code I was working on. 

I ended up finding a better solution than to explicitly bind each 
implementation class after binding it to it's interface. 

The problem with injecting an Injector is definitely still there, but there 
is a better solution (in practice and in design). 

Using TonyD's examples, I modifed our code to remove usage of the Injector, 
instead using Provider<> instances. Where Tony has: 

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() 
+ "'.");
    }    
}

The code went on to use the Injector like: 

return f_injector.getInstance(MyInterface.class);

By replacing all of these calls (which made it much more verbose), I made 
the constructor for the "Driver" appear like so: 
public class Driver implements IDriver
{
    private final Provider<MyInterface> pMyInterface;

    @Inject
    public Driver(Provider<MyInterface> pMyInterface)
    {
        this.pMyInterface = pMyInterface;
    }    

    public MyInterface getInstance() {
        return this.pMyInterface.get();
    }
}

This is a very contrived and over-simplified example, but it goes with some 
of Guice's principles in that using the Injector directly should be done 
*only* when absolutely necessary. There are times where we need to use it, 
but thought this I was able to remove all of the extra bind() statements 
from our modules and clean up some unnecessary bloat!

@Dean, I'm sorry if I sound pedantic, but if your solution is requiring you 
to get injector/providers by class name, rather than by Class<?> instances, 
it might be a design issue.

In regards to your solution, I tried to do that first, but then noticed 
that I could do the same thing by using a Provider<MyInterface> where the 
type I needed was in a child module, which then lead me to just remove the 
injector altogether (where possible) also alleviating the issue. 

I hope anyone else who comes back to find this finds it helpful. 

Cheers,

Kevin

On Thursday, 12 July 2012 19:29:35 UTC-4, Dean Elhard wrote:
>
> I ran into a similar issue, where I was using child injectors to build 
> contained environments with certain classes acting as singletons within 
> those environments, and needing the injector to instantiate classes by name 
> within those environments.
>
> My injection of Injector was getting the parent rather than the child.
>
> The solution was a bit bizarre...
>
> As I understand it, when you inject Injector, the value you get is the one 
> that was actually used to inject your class.
> If the class that injects Injector does not inject anything else uniquely 
> bound in the child injector, the responsibility is passed up to the parent 
> injector so you get the parent injector injected.
> I added an Inject of a class bond in the child injector that was not used 
> directly by the class injecting Injector (but would have to be satisfied by 
> classes created using the injected injector) and suddenly I was getting the 
> injector I expected.
>
> e.g.
>
> I changed:
>
> @Inject
> public void initInjector(Injector injector) {
>     this.injector = injector;
> }
>
> to 
>
> @Inject
> public void initInjector(Injector injector, Foo foo) {
>     this.injector = injector;
> }
>
> where Foo is a class with an explicit instance binding in the child 
> injector.  I am not using it, but by injecting it, I force the use of the 
> child injector to inject my class, rather than having it done by the parent.
>
> Hope this helps...
>
>   
> On Thursday, June 21, 2012 9:38:23 PM UTC-6, 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!
>>
>> On Thursday, 21 June 2012 20:58:46 UTC-4, Stuart McCulloch wrote:
>>>
>>>
>>> ^ 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.
>>>
>>> See http://code.google.com/p/google-guice/wiki/BindingResolution
>>>
>>> Note you can tell the binder to require explicit bindings: 
>>> http://google-guice.googlecode.com/git/javadoc/com/google/inject/Binder.html#requireExplicitBindings
>>> ()
>>> 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
>>>
>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice.
For more options, visit https://groups.google.com/d/optout.

Reply via email to