Re: [gwt-contrib] Initial support for @GwtCreate (code-gen methods)
Thank Ray :-) The patch has as an issue with constructor code-gen that I solved, but GIT doesn't allows me to push merges. Of course, has you a link to explore the javac compiler-plugin alternative? Thanks! - Andrés El sábado, 17 de agosto de 2013 01:28:53 UTC-3, Ray Cromwell escribió: Andres, this looks amazing! I've been out this week on vacation but returning tomorrow, I'll take a look when I return. On Fri, Aug 16, 2013 at 2:22 AM, Andrés Testi andres@gmail.comjavascript: wrote: I've been working on a prototype inspired by Ray Cromwell's proposal for @GwtCreate parameters, borrowing some ideas from Scala implicit macros. I apologize for not to post this in the Possible GWT.create() Improvements thread, but this message is too long to be only a comment. You can check my patch at https://gwt-review.googlesource.com/4110. This prototype has passed many JUnit tests cases and works fine (only fails JEnumTypeTest after my last pull, I don't know why). Devmode also works. This proposal differs from Ray's original idea in that @GwtCreate is a parameter annotation instead of a method annotation. Later I will justify this decision. This new proposal consists on rewriting methods adding a trailing implicit parameter of type GwtCreateFactory for each parameter annotated with @GwtCreate. GwtCreateFactory is a hidden interface used by the compiler: interface GwtCreateFactory { T T create(); } When the compiler finds a code-gen method like Foo createFoo(@GwtCreate final Class? extends Foo fooType) { return GWT.create(fooType); } it is rewritten as Foo createFoo(final Class? extends Foo type, GwtCreateFactory fooType$factory) { return fooType$factory.create(); } IMPORTANT: The @GwtCreate parameter requires to be final. This proposal doesn't require constant evaluation expression. The final modifier is required to disable non reproductible side effects. At method call site, an invocation like Foo foo = createFoo(SubFoo.class); is rewritten as class SubFoo$GwtCreateFactory implements GwtCreateFactory { @Override public T T create() { return GWT.create(SubFoo.class); } } Foo foo = createFoo(SubFoo.class, new SubFoo$GwtCreateFactory()); Just like Scala implicit parameters, @GwtCreate can fight against type erasure and subtyping interface FooCreator { T extends Foo T create(@GwtCreate ClassT fooType); } class FooCreatorImpl extends FooCreator { T extends Foo T create(@GwtCreate final ClassT fooType) { return GWT.create(fooType); } } code-gen constructors are supported too class CreateByConstructorT extends Foo { final T instance; public CreateByConstructor(@GwtCreate final ClassT fooType) { instance = GWT.create(fooType); } } Again, as in Scala implicit parameters, nesting is allowed class Foo {} class SubFoo extends Foo {} F extends Foo F createFoo(@GwtCreate final ClassF fooType) { return GWT.create(fooType); } S extends SubFoo S createSubFoo(@GwtCreate final ClassS subFooType) { return createFoo(subFooType); } The decision to locate @GwtCreate on parameters was taken to support mixed code-gen methods F extends Foo, B extends Bar void fooBarCreator(@GwtCreate final ClassF fooType, @GwtCreate final ClassB barType) { foo = GWT.create(fooType); bar = GWT.create(barType); } Note that the @GwtCreate class parameters aren't replaced by GwtCreateFactory as was originally suggested by Ray Cromwell. This provides access to actual parameters. ClassT storedType; T instance; void createFoo(@GwtCreate final ClassT type) { storedType = type; instance = GWT.create(type); } * Further improvements: 1) Support for explicit generators @GwtCreate(generator = FooGenerator.class) We should forbid assignation between parameters that differs in @GwtCreate signature Foo createFoo(@GwtCreate(generator = FooGen.class) final Class? extends Foo) {...} // This will fail Foo forbiddenNesting(@GwtCreate(generator = BarGen.class) final Class? extends Foo fooType) { return createFoo(fooType); } 2) Multiple parameters for GWT.create() by means of @GwtCreate.Param U, O UiBinderU, O createBinder( @GwtCreate(generator = UiBinGen.class) final ClassU uiType, @GwtCreate.Param final ClassO ownerType) { return GWT.create(uiType, ownerType); } @GwtCreate.Params must respect the same kind of signature rules than @GwtCreate, and a strict order of invocation // Good ordering Foo createFoo( @GwtCreate final Class? extends Foo fooType, @GwtCreate.Param final Class? arg1, @GwtCreate.Param final Class? arg2) { return GWT.create(fooType, arg1, arg2); }
Re: [gwt-contrib] Initial support for @GwtCreate (code-gen methods)
BTW consider that I forgot to commit @GwtCreate annotation, you can find it here: https://gwt-review.googlesource.com/#/c/4111/ Where I wrote Further Improvements, I meant Upcoming Improvements (I'm not native english speaker) - Andrés -- http://groups.google.com/group/Google-Web-Toolkit-Contributors --- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
[gwt-contrib] Re: Initial support for @GwtCreate (code-gen methods)
I like it! I've got a few comments / ideas, but overall, I'm glad to see more work being done to empower core GWT functionality. Note that the @GwtCreate class parameters aren't replaced by GwtCreateFactory as was originally suggested by Ray Cromwell. This provides access to actual parameters. It would be possible to do a full replacement if the factory also gave access to the class field, and any code in the method block accessing the class could be re-routed through the factory. Though, I see no good reason why to do the extra work this way, I figured I'd mention it in case someone else has a use case for it. * Upcoming improvements: 1) Support for explicit generators @GwtCreate(generator = FooGenerator.class) Did you see my pull request with some (very) basic support for this? https://gwt-review.googlesource.com/#/c/4000/ We should forbid assignation between parameters that differs in @GwtCreate signature Foo createFoo(@GwtCreate(generator = FooGen.class) final Class? extends Foo) {...} Agreed. Final isn't necessary to trace values, but it does ensure users don't get weird behavior. 2) Multiple parameters for GWT.create() by means of @GwtCreate.Param U, O UiBinderU, O createBinder( @GwtCreate(generator = UiBinGen.class) final ClassU uiType, @GwtCreate.Param final ClassO ownerType) { Is the intention here to just send more classes to the generator, or to actually send parameters to the constructor of the rebound object being instantiated? Foo createFoo( @GwtCreate final Class? extends Foo fooType, @GwtCreate.Param final Class? arg1, @GwtCreate.Param final Class? arg2) { return GWT.create(fooType, arg1, arg2); } Sending classes is no good, because the constructor needs the values. Personally, I think the best solution is to add the parameters to @GwtCreate; Foo createFoo( @GwtCreate({String.class, int.class}) final Class? extends Foo fooType, String arg1, int arg2) { return GWT.create(fooType, arg1, arg2); } Class values in annotations must be class literals, so that makes that easy. It also means we don't care about the order of extra parameters sent to the method, nor are we forced to get these values from the method parameters (or even declare GWT.create params as params in method); the invocation of GWT.create(cls, params) would simply supply the JExpressions to pass along to constructors. (Have to pull out the initializers from the JNewArray made by the generics, but that's simple). I assume we would be changing GWT.create to be create(Class? c, Object ... params); the compiler could bail if params.length 0 anywhere that's not in a method (method w/ parameter) annotated with @GwtCreate. Then, add a JType[] and JExpression[] to JGwtCreate to be able to find the right constructor and have values to send it (not sure if unboxing would work without a tweak, but that's no biggie). The only hard-ish part would be updating ResolveRebinds to pass along the list of JExpressions correctly. Do you have any work started in this area, cos I'd be glad to give it a shot / send over a pull request. To allow mixed multiple code-gen parameters, we would bind main parameters by name F extends Foo, B extends Bar void mixedMultiple( @GwtCreate final ClassF fooType, @GwtCreate.Param(fooType) final Class? fooArg, @GwtCreate final ClassB barType, @GwtCreate.Param(barType) final Class? barArg) I really don't like this much typing to wire stuff up. Putting the params in the @GwtCreate would make this much cleaner: F extends Foo, B extends Bar B create( @GwtCreate({String.class}) final ClassF fooType, @GwtCreate({Foo.class}) final ClassB barType) { F foo = GWT.create(fooType, some string); return GWT.create(barType, foo); // params can come from anywhere } 3) Support for GWT.create(this.getClass()) ? not exactly, but... Explicits generators can eliminate the issue of the unique generator per class hierarchy. An aditional boolean parameter for @GwtCreate would mitigate the code size issue abstract class UiBinderComposite extends UiBinderComposite { public UiBinderComposite() { UiBinderWidget, UiBinderComposite binder = createBinder(getClass()); } private static UiBinderWidget, UiBinderComposite createBinder(@GwtCreate( // The explicit generator knows when to stop the code generation generator = UiBinderCompositeGenerator.class, // this.getClass() is disallowed by default. allowsThisClass = true) final Class? extends UiBinderComposite type) { return GWT.create(type); } } I am unsure how