On Thu, Nov 4, 2010 at 3:37 PM, Philippe Beaudoin <
[email protected]> wrote:

> On Thu, Nov 4, 2010 at 12:01 PM, Sam Berlin <[email protected]> wrote:
> > On Thu, Nov 4, 2010 at 1:00 PM, Philippe Beaudoin
> > <[email protected]> wrote:
> >>
> >> Just to come back on one of my questions: is injection automatically
> >> performed on the fields and methods of instances bound with
> >> toInstance()?
> >
> > Yup, injection is automatically performed on fields & methods for
> providers
> > (provided they are bound as toProvider(..)).
>
> And toInstance too? Neat!
>
> >> Thanks for pointing out the MembersInjector. In this case I don't
> >> think I can use it however, for two reasons. Tell me if I'm wrong:
> >> 1) My SpyProvider is generic, so I would need to inject a
> >> MembersInjector<T>. Would this work?
> >
> > Yup!  It's a pretty neat feature.  Another thing you can do is inject a
> > TypeLiteral<T> if you have any need to inspect details of T at runtime.
>
> Awesome! Injecting TypeLiteral<T> looks like a very powerful idea!
>
> >> 2) I instantiate T using its @Inject constructor if present, so I need
> >> to be able to instantiate T's dependencies that appear only in the
> >> constructor parameter list. I don't think these dependencies can be
> >> instantiated with the MembersInjector?
> >
> > MembersInjector will only replace the need to call injector.injectMembers
> > (replacing it with membersInjector.injectMembers).  If you want to
> replace
> > the injector.getInstance(..) calls for constructor dependencies, you
> would
> > have to iterate through the dependencies in SpyProvider's constructor and
> > could call binder().getProvider(dependency.getKey()) for each dependency,
> > then call provider.get() for each and construct your instance with those.
>
> If I do this in SpyProvider's constructor, wouldn't this force me to
> make sure all dependencies of T's constructor are bound _before_ I
> bind SpyProvider? I really like the fact that my current
> implementation is independent of the binding order, as long as the
> injector has access to all the dependencies when SpyProvider.get() is
> called.
>

Nope.  All bindings are processed & understood *before* any injection is
attempted.  The order of bindings doesn't matter at all.


>
> >  But!... you may want to look into toConstructor bindings, which may
> obviate
> > the whole need for any of this.  An example:
> >
> >
> bind(Foo.class).annotatedWith(Internal.class).toConstructor(InjectionPoint.forConstructorOf(FooImpl.class).getMember());
> >  bind(Foo.class).toProvider(new
> > SpyProvider<Foo>(getProvider(Key.get(Foo.class, Internal.class)));
> >  class SpyProvider<T> {
> >        private final Provider<T> internalProvider;
> >        SpyProvider(Provider<T> p) {
> >          this.internalProvider = p;
> >        }
> >       T  get() {
> >            return spy(internalProvider.get());
> >        }
> >    }
>
> I have been trying many variations around your proposal (with an
> @Internal annotation). In all cases I ran into the dreaded stack
> overflow because SpyProvider<> was being injected into himself. As you
> can see, my solution was to more or less rewrite Guice's injection
> code to instantiate constructor dependencies myself.
>
> Looking at the code you propose I have a number of questions:
> 1) Can you call getProvider(Key.get(Foo.class, Internal.class)) on the
> binder even before the injector is created?
>

Yup.  You won't be able to _use_ the provider until the Injector is created,
but binder.getProvider(..) will always return a provider.  It's also nice
because if no binding is found (and no JIT binding can be created), you'lll
fail at injector-creation time with a good error message.


> 2) Why is toConstructor needed here? I would be happy with:
> bind(Foo.class).annotatedWith(Internal.class).to(FooImpl.class);
>

Good catch.  It technically isn't needed in my example.  But, consider the
case where it's not split between Foo -> FooImpl, or if FooImpl was scoped
(as, say, a @Singleton annotation on FooImpl).  If it had a scoping
annotation, toConstructor basically ignores that scope.  For concrete
classes, you need toConstructor because otherwise you'll get recursion.
 Consider:
  bind(ConcreteFoo.class).annotatedWith(Internal.class).to(ConcreteFoo.class);
  bind(ConcreteFoo.class).toProvider(new
SpyProvider(getProvider(Key.get(ConcreteFoo.class, Internal.class)));

ConcreteFoo is bound to SpyProvider, which will be using a Provider of
"@Internal ConcreteFoo", which is bound to ConcreteFoo... and then repeat.

Using toConstructor(...) in the first binding gets rid of the recursion,
because "@Internal ConcreteFoo" is bound to a "constructor of ConcreteFoo".

sam


> Thanks a lot for your input Sam, it really help me get a better
> understanding of Guice's little known features.
>
> Cheers,
>
>    Philippe
>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-guice%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to