On Tue, Aug 10, 2010 at 9:04 AM, Peter Schmitt <[email protected]> wrote:
> Hi all, > > this topic comes up so often that we should really find a solution. :) The > short story is that we might need to fix this issue but could potentially > work without it: > http://code.google.com/p/google-gin/issues/detail?id=95(Allow classes created > by a Generator to participate in dependency > injection) > > Long story: > > >> When you start creating multiple Ginjectors, instances of classes don't >> stay the > > same. For example, a Singleton EventBus in two Ginjectors are >> different instance types. >> > > If you inject your ginjector somewhere in its own dependency tree, it will > inject itself, i.e. it is automatically bound as a singleton. > > >> Also, I'm pretty sure you can't put an @Inject on an interface method, >> but I haven't tried. >> > > Yes, you can - this is explicitly allowed in Gin for use with Generators. > > > Would something like the following improve life for GIN users enough to >> be >> > worth doing? Or is it just a hack? >> > [...] >> > > I think this is perfectly viable - but we're running into the generator > interaction issue here. Right now, Gin cannot use generated code as input > and therefore will not be able to inspect the generated implementation of > MyUiBinder. This could be fine if we were specifying exactly what we want to > be injected into the factory. But as far as I can see, you're injecting the > ginjector and then using it in generated code. How do you know how to > retrieve objects from the Ginjector? In difference to Guice, there is *no > *getInstance(..) method on a Ginjector. > I think the scheme I sketched gets around this issue. Gin isn't aware of any of the generated code. Rather, the generated code is aware of the public Ginjector interface. When Gin is asked to inject a MyUiBinder, it's just going to write GWT.create(MyUiBinder), and then call that instance's setFactory() method with itself. So this code: @Inject public MyWidget(MyUiBinder binder) extends Composite { public interface MyUiBinder extends UiBinderWithFactory<Widget, MyWidget, MyGinjector> { @Inject setFactory(MyGinjector factory); } } makes Gin generate the moral equivalent of new MyWidget((MyUiBinder.class) GWT.create(MyUiBinder.class)).setFactory(this); Similarly, UiBinder is aware of the public interface of my public Ginjector. That's why the JavaDoc says that the factory is required to provide an explicit FooWidget getTheFoo() if it is to be a source of FooWidgets. You the developer put this method on your Ginjector: public interface MyGinjector extends Ginjector { FooWidget getFoo(); } And so UiBinder can generate something like: HTMLPanel h = new HTMLPanel("Blah di blah di blah <span id='foo25'/> di blah."); h.addAndReplaceElement(factory.getFoo(), "foo25"); Also, while I was assuming that for the most part the binder would be working off of the Ye One True Ginjector, there is no actual requirement that you do so, nor that your Factory be Ginjector at al. E.g.: @Inject public MyWidget(MyUiBinder binder) extends Composite { public static class Factory { @Inject @MagicScope EventBus eventBus; FooWidget makeAFoo() { return new Foo(eventBus); } } public interface MyUiBinder extends UiBinderWithFactory<Widget, MyWidget, MyGinjector> { @Inject setFactory(Factory factory); } } And if it's possible for one Ginjector to create another (haven't been paying attention, sorry), that boilerplate could perhaps be even less? @Inject public MyWidget(MyUiBinder binder) extends Composite { @MagicScope public interface Factory extends Ginjector { EventBus eventBus; } public interface MyUiBinder extends UiBinderWithFactory<Widget, MyWidget, MyGinjector> { @Inject setFactory(Factory factory); } } > I think what we want is a class generated by UiBinder that has @Inject > annotated constructor/fields/methods for its required children and is then > used as input by the Gin generator to wire the injection up. But to > accomplish that, we'll need to fix the issue mentioned above. > > How does this sound? > Like it would need a lot more thought and a lot more work :-). (Although it's a nicely DI-framework-agnostic notion, now that the annotations live in javax.). We really wouldn't just want limit you to putting @Inject on everything, you'd want the full gin experience — e.g. to be allowed to put other annotations on specific fields, right? All of a sudden we have to provide an annotation syntax for ui.xml. Don't get me wrong, I would rather fix GWT.create() so that Ginjector actually could efficiently provide a getInstance(...) method, and to allow gin to see generated code. But those two conversations never seem to terminate, and I don't have the chops to just do them myself. So my question is: if we accept the current limitations, would this change be a worthwhile incremental step? > > Peter > > > > >> > public interface UiBinderWithFactory<U, O, F> extends UiBinder<U, O> { >> > /** >> > * Sets a factory to use when instantiating objects that are not >> > * provided via @UiFactory methods or @UiField(provided = true) >> fields. >> > * <p> >> > * When an instance is needed, a zero args method with an appropriate >> > return type >> > * will be sought on the factory to provide it. If none is found >> > GWT.create() >> > * will be used instead. >> > * <p> >> > * It is a compile time error for the factory to provide ambiguous >> > methods. >> > */ >> > setFactory(F factory); >> > } >> > >> > You might wind up with code like… >> > >> > @Inject >> > public MyWidget(MyUiBinder binder) extends Composite { >> > >> > public interface MyUiBinder extends UiBinderWithFactory<Widget, >> MyWidget, >> > MyGinjector> { >> > @Inject setFactory(MyGinjector factory); >> > } >> > >> > …and a few extra getters on your Ginjector. >> > >> > Now injecting an injector is generally a terrible idea, but it's >> something >> > at least. (Does that even work in Gin? And can you put @Inject on an >> > interface method?) >> > What do you think? >> > rjrjr >> > >> > -- >> > http://groups.google.com/group/Google-Web-Toolkit-Contributors >> >> -- >> You received this message because you are subscribed to the Google Groups >> "google-gin" group. >> To post to this group, send email to [email protected]. >> To unsubscribe from this group, send email to >> [email protected]<google-gin%[email protected]> >> . >> For more options, visit this group at >> http://groups.google.com/group/google-gin?hl=en. >> >> > -- > http://groups.google.com/group/Google-Web-Toolkit-Contributors > -- http://groups.google.com/group/Google-Web-Toolkit-Contributors
