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.