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.
