Thursday, March 12, 2009

Relaxing constraints on GWT.create()

Recently I've been playing around with some GWT ideas that really cry out for a more liberal deferred binding system. Currently, GWT imposes the restriction that deferred binding can only happen through the GWT.create() method. There's a couple of problems with this:


  1. Can't narrow type signature for custom library

  2. Can't create a method to decorate the returned result

  3. Can't parameterized or override the bindings at callee site



To illustrate this, I've compiled some motivation examples.

RPC requests signed by OAuth



interface MyService extends RemoteService<MyServiceAsync> { ... }
// example call
OAuth.withSignature(MyService.class).method1(arg1, arg2, asyncCallback);



public class OAuth {
@GwtCreate // method must be static, class parameter must be final
public static <S, T extends RemoteService<S>> S withSignature(final Class<T> service) {
// GWT.create with non-literal ONLY allowed
// if enclosing method is @GwtCreate and
// variable statically resolvable to literal param
S async = GWT.create(service);
((ServiceDefTarget)async).setRequestBuilderCallback(new OAuthRequestBuilderSigner());
return async;
}
}

Currently today, it would look like this:

MyServiceAsync foo = GWT.create(MyService.class);
RequestBuilder rb = foo.method1(arg1, arg2, asyncCallback);
OAuthRequestBuilderSigner.sign(rb);
rb.send();


The tight coupling at the callsite also makes it difficult to swap out implementations easy (like using AuthSub, or one of the other 4 Google Friend Connect auth techniques). An alternative is to make a separate subtype of each with a custom generator, e.g.

MyServiceOAuth extends MyService, GWT.create(MyServiceOAuth.class)

I'd argue that the above gets cumbersome with multiple services and multiple authentication types. I've taken some liberties above by adding a type parameter to RemoteService to make the return type statically resolvable, as well as allowing a global callback mechanism on ServiceDefTarget for RequestBuilder override. Note that type-safety is ensured, one can't call this method with something that is not a RemoteService, and it will be flagged at edit-time in your IDE.

An EasyMock library for Hosted/Web Mode



Subscriber mock = GMock.mock(Subscriber.class);
publisher.add(subscriber);
//...
GMock.replay(mock);

public class GMock {
// selectively override module binding rules ONLY for this method
@GwtCreate(generator=com.gmock.rebind.GMockGenerator.class)
public static <T> T mock(Class<T> toMock) {
return GWT.create(toMock);
}
}


In this method, the mock() method acts like GWT.create() except that it overrides the current binding rules, forcing the specified generator.

GWT Exporter



Exporter.export(Foo.class);

public class Exporter {
@GwtCreate
public static <T extends Exportable> void export(Class<T> exportable) {
ExporterImpl ximpl = GWT.create(exportable);
ximpl.export();
}
}

Note, the type safety, one can't try to Export a non-exportable class. This will be flagged at edit time in the IDE.

GIN/Guice dependency injection



Processor pimpl = Gin.inject(Processor.class, TestProcessorModule.class);

public class Gin {
@GwtCreate(generator = com.google.gin.rebind.GInjectorGenerator)
public static <T, S extends AbstractGinModule>
T inject(Class<T> interf, @GwtCreateParam Class<S> module) {
return GWT.create(interf, module);
}
}

This one is more controversial, but allows GWT.create() to be parameterized by literal metadata that is available to the generator. This is semantically equivalent to what we have today:

@GinModule(TestProcessorModule.class)
interface MyTestInjector extends GInjector {
Processor getProcessor();
}

but without the need to actually write the interface.

Combing compile-time and run-time parameters


Final example, mix-and-match both compile-time variables and run-time variables:


OAuth.withSignature(MyService.class, debugMode ? "/debugService" : "/MyService").method1(arg1, arg2, asyncCallback);

public class OAuth {
@GwtCreate // method must be static, class parameter must be final
public static <S, T extends RemoteService<S>>
S withSignature(final Class<T> service, String endPoint) {
// GWT.create with non-literal ONLY allowed if enclosing method is
// @GwtCreate and variable statically resolvable to literal param
S async = GWT.create(service);
((ServiceDefTarget)async).setRequestBuilderCallback(new OAuthRequestBuilderSigner());
((ServiceDefTarget)async).setServiceEntryPoint(endPoint);
return async;
}
}

Friday, March 6, 2009

Spring cleaning and the blog

To try and improve readability and reach, I made a few changes today:

1) Re-enabled SyntaxHighlighter for code snippets
2) Widened the width of the main content to 600px (for code blocks)
3) removed Twitter and added Google Friend Connect
4) enabled CAPTCHA to reduce comment span
5) tweak some colors so the subsections are easier to read.

If you have any other advice for improving the Look and Feel, leave a comment.

-Ray

Thursday, March 5, 2009

Structural Typing for GWT and Javascript

In a previous post I described a type of impedance mismatch between Javascript and Java idioms that makes the GWT Exporter still less than ideal for supporting Javascript programmers. A short illustrative (but contrived) example:


public class Customer implements Exportable {
private String firstName, lastName;
@Export String getFirstName() {
return firstName;
}

@Export void setFirstName(String fn) {
firstName = fn;
}

@Export String getLastName() {
return lastName;
}

@Export void setLastName(String ln) {
lastName = fn;
}
}

Today, you may use this export in Javascript like this:

var cust = new Customer();
cust.setFirstName("Ray");
cust.setLastName("Cromwell");
Processor.doSomething(cust);

The example is contrived because you could use a constructor, but with more complex objects with nested types, you wouldn't use a constructor, but either a builder pattern, or inject the types after construction.

Javascript developers however don't work in the world of Javabean interfaces, they prefer easy construction of configuration/builder information via object literals:

Processor.doSomething({firstName: "Ray", lastName: "Cromwell"})


Moreover, when passing in say, a bind of event callbacks, they'd prefer to write:

foo.addEvents({
click: function(e) { ... }
move: function(e) { ... }
drop: function(e) { ... }
});

The challenge is to seemlessly bridge this idiomatic mismatch between JS and Java GWT code without actually having to write much bridging code or adapters.

Structural Typing


Java is a manifestly typed language. All types have to be declared, and type checking is done by explicit hierarchy. Javascript is a dynamically typed language, with essentially no type checking at all. Orthogonal to this is the concept of Structural Typing. Haskell, ML, and Scala are all examples of languages which support structural typing. Structural typing was also planned for Javascript 2 before it got killed.

So what's a structural type? Recall the Customer example from the previous section. It was a class with two fields, firstName, and lastName, both Strings. If Java supported a structural type system, I could declare a method in two ways:

public void process(Customer cust) { ... }

public void process({firstName: String, lastName: String} cust) { ... }

In this invented syntax, the cust parameter to the second process() function is an anonymous type, we don't know its real name. However, we are stating that as long as it consists of two fields named "firstName", and "lastName", and the types are both Strings, then we can access these fields and treat it like a Customer (although it may not be one)

Hmm....I smell an idea...

Structural Type Exports


What if I rewrite the Customer POJO class with a @StructuralType annotation:

@Export
@StructuralType
public class Customer implements Exportable { ... }

The dispatch code for an exported process() function could then look like this:

$wnd.Processor.prototype.process = function(cust) {
if(cust instanceof $wnd.Customer && isExportedInstance(cust)) {
// JSNI dispatch to @Processor::process(LCustomer;)(unwrap(cust));
}
else if(typeof(cust) == 'object') {
// cust is not an instance of the Customer POJO, but an object
if(cust.firstName != undefined && cust.lastName != undefined) {
var scust = new Customer();
scust.setFirstName(cust.firstName);
scust.setLastName(cust.lastName);
@Processor::process(unwrap(scust));
}
}
}

The GWT compiler would auto-inject this structural type check and initialization code simply by annotating a parameter or return type involved with @StructuralType

Refinements to the idea


Taking this a step further, one could override the expected type literal field names to be checked

@SType("fn")
public void setFirstName(String firstName) { ... }
@SType("ln")
public void setLastName(String lastName) { ... }

which would allow the object literal to be specified as {fn: "Ray",ln: "Cromwell"}. Another extension would allow partial matches to succeed with default values supplied:

@Optional("Ray")
public void setFirstName(String firstName) { ... }

which would reduce the structural type to just a lastName field for matching purposes, but would allow the specification of firstName to be supplied and injected into the setter as "Ray" if it wasn't present.

Structurally Typed Interfaces


GWT Exporter already supports closure conversion for single-method Java interfaces. That is, if the following interface:

public interface MyCallback {
public void go(Object arg);
}

occurs as a type parameter in an exported method, the Javascript developer may supply function(arg) { ... } and the GWT generated bridge code will automatically convert this into a GWT object instance that implements the MyCallback interface type. What it cannot support is the example given earlier:

foo.addEvents({
click: function(e) { ... }
move: function(e) { ... }
drop: function(e) { ... }
});

which would represent something like:

public interface MyEventHandler {
public void onClick(Event e);
public void onMove(Event e);
public void onDrop(Event e);
}

However, using structural typing conventions, and an @StructuralType annotation on an interface, we can auto-convert object literals containing multiple function closures into a Java interface for GWT.

I am still working out the details of the full overload resolution algorithm for overloaded function types, but some version of this proposal will make it into GWT Exporter 3.0.

-Ray

GWT Exporter 2.05 released

The release adds two new features:

1) arrays are return types or parameters supported, that is:


@Export public double[] getFoo() { }
@Export public SomeExportable[] getBar() {}
@Export public void setFoo(double[] foo) { }
@Export public void setBar(SomeExportable[] bar) { }


now works, in both Web mode and Hosted Mode.

2) Export Overlays implemented. This means you can now Export classes you don't own.

@ExportPackage("gwt")
public interface WindowExport extends ExportOverlay<Window> {
@Export void alert(String s);
}

will export the GWT Window class into the namespace $wnd.gwt.Window, and export the alert() method of this class.

The JARs are downloadable from: http://timefire-repository.googlecode.com/svn/mavenrepo/org/timepedia/exporter/gwtexporter/2.05/

Tuesday, March 3, 2009

What's next for GWT Exporter?

I have learned over the past year that a lot of Chronoscope users like to use the Javascript API, but the current API is unfortunately, a small sliver of the full power the GWT API offers. In dealing with increasing demand for more exported functions, I have run into some basic limitations that GWT-Exporter has that make it less than ideal for exporting idiomatic Javascript APIs.

Exporting Classes you don't control


Since Chronoscope made the switch to the new GWT Incubator/GWT 1.6 Event handling system, I have been unable to export event handler functions, because the HandlerRegistration type returned by the GWT event system is not an interface, making it difficult to wrap. In general, if you don't own a class, you can't add Exporter annotations to it, which is problematic because there are lots of types you don't control.

A new mechanism will be added in an upcoming GWT Exporter release, I dub Export Overlays, which will work something like this:

@ExportPackage("gwt")
public interface WindowExport extends ExportOverlay<Window> {
@Export void alert(String message);
}

In the above code, we are exporting the GWT Window class in the Javascript package "gwt", but only exposing the alert() method. This will result in an exported wrapper in $wnd.gwt.Window with the method published on $wnd.gwt.Window.prototype.alert.

Fine control over Javascript->Java type conversions


Javascript doesn't support overloaded method dispatch as a language feature, but most Javascript libraries do use heavily overloaded functions with variable arguments and variable argument types. Currently, GWT Exporter supports Javascript overloading by arity, but not by type, so two Java methods of the same name and identical arity cannot be exported without overriding the exported name.

Some of this will be mitigated by adding in automatic type checking for handling overloaded dispatch, but more is needed. Consider the following Javascript API:

plot.addHandler({
onMove: function(event) { }
onHover: function(event) { }
onFocus: function(event) { }
});

This is somewhat idiomatic Javascript, leveraging object literals to pass in multiple bindings. The current approach is to have 3 methods, addMoveHander, addHoverHandler, addFocusHandler, but this doesn't feel quite right to some Javascript programmers. Another problem is illustrated below:

@Export
public class Foo implements Exportable {
public void setFoo(Date date) { }
}

A Javascript developer would naturally want to write:

var date = new Date();
foo.setFoo(date);

But this won't work, because there is no automatic conversion in GWT Exporter between JS Date and java.util.Date. I could add this (as was done with JS String and java.lang.String), but that still leaves open the problem of the inability to pass Javascript types from third party Javascript libraries into GWT methods.

Type Converter injection


What I'm currently looking at is a mechanism to declare Javascript fragments on Java methods which can type-convert arguments between the exported wrapper, before they invoke the underlying GWT method. Something like this:

@Export
public class Foo implements Exportable {
public void setFoo(@Convert(JsType.DATE, "new java.util.Date($_arg.getTime()$)") Date foo) { }
}

The syntax is still subject to change of course, but the idea is that you supply an annotation on each param, using an enum (STRING, FUNCTION, ARRAY, OBJECT, etc) which corresponds to the return value of the 'typeof' operator, or you use a special INSTANCE version which allows you to specify a match according to 'instanceof'. Next, you supply a Java expression), including inline JSNI code (here shown in between $ $). The GWT Exporter then arranges to generate code to check the type, and inject your fragment before calling the underlying method.

Another possibility is to add JSNI methods to Export Overlays which allow arbitrary conversion code to be specified and injected into the wrapper prior to invocation of methods.

By combining this with the Export Overlay concept, it might be possible to deal with the idiomatic JS Literal pattern, while keeping JSNI methods out of classes that may not want them, or that you do not control.

Primitive arrays an oversight


Finally, GWT Exporter currently does not support export of parameters or return types which are native Java arrays, which is a hole in the export type system. This will be added in a near future release.

-Ray