GWT best Practices - JS Library Wrappers & Overlay Types

2,946 views
Skip to first unread message

Bobby

unread,
Apr 18, 2009, 4:24:06 PM4/18/09
to Google Web Toolkit
I'm in the process of trying to dynamically generate a GWT wrapper for
an existing JS library and i have a few questions which come down to
best practices for the most part.

1. When wrapping a JS library with GWT, is it recommended to leave the
namespaces intact? If the JS library and the GWT wrapper library have
the same namespaces, is there a chance of a conflict where GWT code
will overwrite the original namespaces of the JS library? (i don't
think this is the case but i wanted to verify)

2. If the JS library that's being wrapped around has classes that may
need to be constructed from the Java side, then are Overlay Types
automatically out of the question (in which case plain Java wrapper
classes would be used) or is it better to still use Overlay Types and
just expose factory methods for doing the job of the constructors?

3. If the original JS library has classes where fields are commonly
accessed directly, as opposed to via getters and setters, then is it
recommended to remain faithful to the original JS library and expose
the fields without getters/setters (in which case Overlay Types are
out of the picture) or ignore this aspect of the original JS library
and expose getters/setters instead.

4. If the original JS library has a method that has optional
parameters, for example, myFunc(a, b) where b may be undefined, should
a single Java method be added, or should multiple overloaded methods
be used? For example:
myFunc(a)
myFunc(a, b)

5. Should constants be automatically converted to enumerations or
should they just be left alone?

If you have some insight on these questions (or any others i missed) i
would really welcome your input.

Bobby

unread,
Apr 19, 2009, 4:42:46 PM4/19/09
to Google Web Toolkit
One more for the list:

6. When the original JS library contains one or more classes with
methods that receive functions as parameters, what is the best way to
implement these methods? Should there be a generic Function or
Callback class on the GWT side that is used as the function parameter
type? The function that is passed to the JS method may expect to
receive a different number of parameters itself, so one option is to
define the following class in Java:

public class GenericCallback(){
public void Execute(Object[] Parameters){
...
}
}

With this approach the following JavaScript method:

function doSomething(myCallback){}

Would be translated to the following in GWT:

public final native void doSomething(GenericCallback myCallback)/*-{
var cb = function(a, b, c, d, e){
var pars = [a,b,c,d,e];//something fancier than this
var jcb = this.handler;
@jcb.GenericCallback::Execute([Ljava/lang/Object;)(pars);
}
cb.handler = myCallback;//or something like this that actually
works
this.doSomething(cb);
}-*/

I don't like the idea of joining all the parameters in an array or of
having a function in Java receive an object array, but otherwise there
would need to be multiple Execute methods with a different number of
parameters or even multiple Callback classes in Java, each with its
own particular Execute method. This wouldn't be so difficult if i was
generating the code manually.

Here's a concrete example of what i'm talking about:
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html

This class has methods that receive function callbacks (for example
deleteEntry). If you were trying to auto generate a GWT wrapper for
that class how would you handle the methods that receive Function
parameters? (assuming that we're using Overlay Types for the
wrapping).

Bobby

Thomas Broyer

unread,
Apr 19, 2009, 7:07:08 PM4/19/09
to Google Web Toolkit


On 18 avr, 22:24, Bobby <bobbysoa...@gmail.com> wrote:
> I'm in the process of trying to dynamically generate a GWT wrapper for
> an existing JS library and i have a few questions which come down to
> best practices for the most part.
>
> 1. When wrapping a JS library with GWT, is it recommended to leave the
> namespaces intact? If the JS library and the GWT wrapper library have
> the same namespaces, is there a chance of a conflict where GWT code
> will overwrite the original namespaces of the JS library? (i don't
> think this is the case but i wanted to verify)

There's no notion of "namespaces" in the Javascript code resulting
from GWT compilation (actually, there's no notion of "namespaces" in
JavaScript either, at all, but that's just a problem of vocabulary).
Even when compiling in -style PRETTY or DETAILED, GWT shouldn't
override/shadow any JavaScript variable defined outside the GWT code
(everything's initialized in a closure to not polute the global scope,
and in JSNI you should use $wnd.XXX to access a variable called XXX
defined in the global namespace, so...)

> 2. If the JS library that's being wrapped around has classes that may
> need to be constructed from the Java side, then are Overlay Types
> automatically out of the question (in which case plain Java wrapper
> classes would be used) or is it better to still use Overlay Types and
> just expose factory methods for doing the job of the constructors?

Overlay types have no overhead, at all, compared to wrapper classes,
so prefer overlay types and static factory methods.

> 3. If the original JS library has classes where fields are commonly
> accessed directly, as opposed to via getters and setters, then is it
> recommended to remain faithful to the original JS library and expose
> the fields without getters/setters (in which case Overlay Types are
> out of the picture) or ignore this aspect of the original JS library
> and expose getters/setters instead.

See answer to 2; yes, use getters/setters in Java overlay types, I
repeat: there's no overhead implied!

> 4. If the original JS library has a method that has optional
> parameters, for example, myFunc(a, b) where b may be undefined, should
> a single Java method be added, or should multiple overloaded methods
> be used? For example:
> myFunc(a)
> myFunc(a, b)

You can use overloads.

> 5. Should constants be automatically converted to enumerations or
> should they just be left alone?

As you like. There are many ways to map JS constants to GWT Java; all
imply an overhead, except if you hard-code the constant value as a
constant Java field, or if you provide a static getter method that
returns the JS constant using JSNI.

> If you have some insight on these questions (or any others i missed) i
> would really welcome your input.


On 19 avr, 22:42, Bobby <bobbysoa...@gmail.com> wrote:
> One more for the list:
>
> 6. When the original JS library contains one or more classes with
> methods that receive functions as parameters, what is the best way to
> implement these methods? Should there be a generic Function or
> Callback class on the GWT side that is used as the function parameter
> type?

Functions are not a first-class citizen in Java, so you have to use
interfaces or abstract classes or... and in your JSNI code, pass a
function as the argument that will call back the... callback ;-)

I wouldn't use a generic Callback interface though. One of the
advantages of working with Java is static typing: if you use specific
interfaces, your IDE will flag an error if you pass an erroneous such
callback instance as an argument to a method (and now that the Google
Plugin for Eclipse checks the JSNI code as well and allows for
autocompletion there, there really is not reason not to do it; apart
for the fear of the overhead implied by adding such an interface --
very minor, compared to the number of classes implementing those
interfaces, and probably quickly overweighted by the additional checks
that you'd have to make in your callback instances)

> The function that is passed to the JS method may expect to
> receive a different number of parameters itself, so one option is to
> define the following class in Java:
>
> public class GenericCallback(){
> public void Execute(Object[] Parameters){
> ...
> }
>
> }
>
> With this approach the following JavaScript method:
>
> function doSomething(myCallback){}
>
> Would be translated to the following in GWT:
>
> public final native void doSomething(GenericCallback myCallback)/*-{
> var cb = function(a, b, c, d, e){
> var pars = [a,b,c,d,e];//something fancier than this
> var jcb = this.handler;
> @jcb.GenericCallback::Execute([Ljava/lang/Object;)(pars);
> }
> cb.handler = myCallback;//or something like this that actually
> works
> this.doSomething(cb);
>
> }-*/

public final native void doSomething(GenericCallback myCallback)/*-{
var that = this;
this.doSomething(function(a, b, c, d, e) {
@jcb.MyClass::doSomethingCallback(Ljcb.GenericCallback;IIIII)
(myCallback);
});
}-*/

private static void doSomethingCallback(GenericCallback callback, int
a, int b, int c, int d, int e) {
UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler
();
if (handler == null) {
doSomethingCallbackImpl(callback, a, b, c, d, e);
} else {
doSomethingCallbackAndCatch(handler, callback, a, b, c, d, e);
}
}

private static void doSomethingCallbackImpl(GenericCallback callback,
int a, int b, int c, int d, int e) {
callback.onSomething(a, b, c, d, e);
}

private static void doSomethingCallbackAndCatch
(UncaughtExceptionHandler handler, GenericCallback callback, int a,
int b, int c, int d, int e) {
try {
doSomethingCallbackImpl(callback, a, b, c, d, e);
} except (Throwable t) {
handler.onUncaughtException(t);
}
}

> I don't like the idea of joining all the parameters in an array or of
> having a function in Java receive an object array, but otherwise there
> would need to be multiple Execute methods with a different number of
> parameters or even multiple Callback classes in Java, each with its
> own particular Execute method. This wouldn't be so difficult if i was
> generating the code manually.
>
> Here's a concrete example of what i'm talking about:http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html
>
> This class has methods that receive function callbacks (for example
> deleteEntry). If you were trying to auto generate a GWT wrapper for
> that class how would you handle the methods that receive Function
> parameters? (assuming that we're using Overlay Types for the
> wrapping).

There would be two interfaces involved, one for the <function(Object)>
and another for the <function(Error)>. If the actual type of the
argument can be implied (or at least approached) at compile-time, or
if it depends on how you're calling the methods, I'd probably use
generics:
interface <T> Continuation<T> {
void onContinue(T scope);
}

But actually, in this particular case, I would use a single interface
with onSuccess and onError methods; you could even re-use the
com.google.gwt.user.client.rpc.AsyncCallback interface, wrapping the
JS "Error" object in a custom Java exception.

Bobby

unread,
Apr 19, 2009, 7:47:42 PM4/19/09
to Google Web Toolkit
Thomas, thanks for the reply that's what i wanted to hear for
questions 1, 2, 3 and 4.

While i have your attention, on #5 and constants Vs enumerations - I
won't know the value of the constants at the time of generating the
wrapper (i think that even if i did i would still rather not have them
hard coded in the wrapper class). This means that i can't have JS
constants become static final fields in the Java class. I guess in the
worst case i could have a single JSNI method for retrieving the value
of a given constant, given the name, or one JSNI method per constant,
but Enums would be much more developer friendly.

Just to put things into context, here's a class that defines some
constants:
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Im.html

Right now, using enums, this is the GWT wrapper that the generator
would yield:

[code]
package google.gdata;
public class Im extends com.google.gwt.core.client.JavaScriptObject {
public final native String getAddress() /*-{ return this.getAddress
(); }-*/;
public final native String getLabel() /*-{ return this.getLabel(); }-
*/;
public final native boolean getPrimary() /*-{ return this.getPrimary
(); }-*/;
public final native String getProtocol() /*-{ return this.getProtocol
(); }-*/;
public final native String getRel() /*-{ return this.getRel(); }-*/;
public final native void setAddress(String address) /*-{ return
this.setAddress(address); }-*/;
public final native void setLabel(String label) /*-{ return
this.setLabel(label); }-*/;
public final native void setPrimary(boolean primary) /*-{ return
this.setPrimary(primary); }-*/;
public final native void setProtocol(String protocol) /*-{ return
this.setProtocol(protocol); }-*/;
public final native void setRel(String rel) /*-{ return this.setRel
(rel); }-*/;

public static enum Constants {
PROTOCOL_AIM ("PROTOCOL_AIM"),
PROTOCOL_GOOGLE_TALK ("PROTOCOL_GOOGLE_TALK"),
PROTOCOL_ICQ ("PROTOCOL_ICQ"),
PROTOCOL_JABBER ("PROTOCOL_JABBER"),
PROTOCOL_MSN ("PROTOCOL_MSN"),
PROTOCOL_QQ ("PROTOCOL_QQ"),
PROTOCOL_SKYPE ("PROTOCOL_SKYPE"),
PROTOCOL_YAHOO ("PROTOCOL_YAHOO"),
REL_HOME ("REL_HOME"),
REL_OTHER ("REL_OTHER"),
REL_WORK ("REL_WORK");
private final String name;
Constants(String name) {
this.name = name;
}
public String value(){ return getConstantValue(this.name); }
private static native String getConstantValue(String name) /*-
{ return google.gdata.Im[name]; }-*/;
}
}
[/code]

So the class would have an inner enumeration that retrieves the values
via JSNI. Right now i have now idea if this works because i don't know
how GWT handles enums, let alone inner enums in an overlay type.

For #6 and Callbacks, i agree that interfaces are much more developer
friendly, but these would be difficult to dynamically generate (for
example, what would the generator name the interface, whould it reuse
interfaces across different methods?). I don't have to auto-generate
100% of the code, in the end there may always be some manual editing,
but it's a pity.
Right now (without constants) 90% of the generated wrapper for
Google.GData compiles, the callbacks are the missing 10%.

Bobby
> JS "Error" object in a custom Java exception.- Hide quoted text -
>
> - Show quoted text -

Thomas Broyer

unread,
Apr 19, 2009, 8:26:38 PM4/19/09
to Google Web Toolkit


On 20 avr, 01:47, Bobby <bobbysoa...@gmail.com> wrote:
>
> While i have your attention, on #5 and constants Vs enumerations - I
> won't know the value of the constants at the time of generating the
> wrapper (i think that even if i did i would still rather not have them
> hard coded in the wrapper class). This means that i can't have JS
> constants become static final fields in the Java class. I guess in the
> worst case i could have a single JSNI method for retrieving the value
> of a given constant, given the name, or one JSNI method per constant,
> but Enums would be much more developer friendly.

There has been some news recently about enums in GWT:
http://code.google.com/p/google-web-toolkit/wiki/EnumOptimizations
http://timepedia.blogspot.com/2009/04/gwts-type-system-is-more-powerful-than.html

> Just to put things into context, here's a class that defines some
> constants:http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Im.html
>
> Right now, using enums, this is the GWT wrapper that the generator
> would yield:
>
> [code]
> package google.gdata;
> public class Im extends com.google.gwt.core.client.JavaScriptObject {
>         public final native String getAddress() /*-{ return this.getAddress
> (); }-*/;

Er, shouldn't it instead be:
public final native String getAddress() /*-{ return this.address; }-
*/;

>         public final native String getLabel() /*-{ return this.getLabel(); }-
> */;
>         public final native boolean getPrimary() /*-{ return this.getPrimary
> (); }-*/;
>         public final native String getProtocol() /*-{ return this.getProtocol
> (); }-*/;
>         public final native String getRel() /*-{ return this.getRel(); }-*/;
>         public final native void setAddress(String address) /*-{ return
> this.setAddress(address); }-*/;

This "return" is not necessary.

>         public final native void setLabel(String label) /*-{ return
> this.setLabel(label); }-*/;
>         public final native void setPrimary(boolean primary) /*-{ return
> this.setPrimary(primary); }-*/;
>         public final native void setProtocol(String protocol) /*-{ return
> this.setProtocol(protocol); }-*/;
>         public final native void setRel(String rel) /*-{ return this.setRel
> (rel); }-*/;
>
>         public static enum Constants {
>                 PROTOCOL_AIM ("PROTOCOL_AIM"),
>                 PROTOCOL_GOOGLE_TALK ("PROTOCOL_GOOGLE_TALK"),
>                 PROTOCOL_ICQ ("PROTOCOL_ICQ"),
>                 PROTOCOL_JABBER ("PROTOCOL_JABBER"),
>                 PROTOCOL_MSN ("PROTOCOL_MSN"),
>                 PROTOCOL_QQ ("PROTOCOL_QQ"),
>                 PROTOCOL_SKYPE ("PROTOCOL_SKYPE"),
>                 PROTOCOL_YAHOO ("PROTOCOL_YAHOO"),
>                 REL_HOME ("REL_HOME"),
>                 REL_OTHER ("REL_OTHER"),
>                 REL_WORK ("REL_WORK");
>             private final String name;
>             Constants(String name) {
>                 this.name = name;
>             }
> public String value(){ return getConstantValue(this.name); }

If the enum's "value" is the same, I'd rather not use this private
field, and instead use name():
public String value() { return getConstantValue(this.name()); }

You could also probably initialize a static map (or at least keep a
reference to the google.gdata.Im object) for slight better perfs:

private static final jso;

static {
jso = initJso();
}
private static native JavaScriptObject initJso() /*-{ return
google.gdata.Im; }-*/;

private static native String getConstantValue(JavaScriptObject map,
String name) /*-{
return map[name];
}-*/;

> So the class would have an inner enumeration that retrieves the values
> via JSNI. Right now i have now idea if this works because i don't know
> how GWT handles enums, let alone inner enums in an overlay type.

I'm almost sure it would work.

In this particlar case, I wouldn't use an enum though, as these
constants are only "sample values" (common values). And I would use
"true Java constants" too.
(FYI, the GData Java Client use constants for these:
http://code.google.com/intl/fr-FR/apis/gdata/javadoc/com/google/gdata/data/extensions/Im.html
)

An example using an enum:
http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/ltgt/gwt/air/core/client/html/HTMLLoader.java
http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/ltgt/gwt/air/core/client/html/HTMLPDFCapability.java

An example using "just constants":
http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/ltgt/gwt/air/core/client/events/Event.java

> For #6 and Callbacks, i agree that interfaces are much more developer
> friendly, but these would be difficult to dynamically generate (for
> example, what would the generator name the interface, whould it reuse
> interfaces across different methods?).

After a quick scan of the GData Java client API, there doesn't seem to
be much callbacks, so in the JS API most if not all callbacks should
be due to its async nature, thus are likely to be a pair of (<function
(Object)> continuation, <function(Error)> opt_errorHandler), which
could be mapped to AsyncCallback or a few AsyncCallback derivatives
(and a hand-coded specialized exception to wrap the Error object).

> I don't have to auto-generate
> 100% of the code, in the end there may always be some manual editing,
> but it's a pity.
> Right now (without constants) 90% of the generated wrapper for
> Google.GData compiles, the callbacks are the missing 10%.

If AsyncCallback covers 90% of those 10%, it lefts only 1% or manual
editing ;-)

(FYI, GWT-in-the-AIR is entirely hand-written)

Bobby

unread,
Apr 19, 2009, 9:56:39 PM4/19/09
to Google Web Toolkit
Thomas, In your reply above you were asking if i shouldn't instead
have:
public final native String getAddress() /*-{ return this.address; }-

Not really because the GData JS library uses getters/setters (which is
nice) so the getAddress method exists on the JS side:
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Im.html#getAddress

I wasn't aware that "return" wasn't necessary (though it makes sense),
this is why i ask stuff.

On constants vs enumerations, ok if constants are good enough for the
Java GData library then they're good enough for me - it saves me the
work of trying to plug the enumeration types into the method
parameters and return values. I'm going to follow the same approach as
in the following link that you provided:
http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/ltgt/gwt/air/core/client/events/Event.java

AsyncCallback seems like a good fit, i counted three classes in the JS
GData library (out of 238) that use callbacks:
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Feed.html
http://code.google.com/apis/gdata/jsdoc/1.8/google/accounts/user.html
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html

The Feed and Entry classes always have a pair of callbacks for success
and failure, the User class uses single onSuccess callbacks - the
onFailure method of the AsyncCallback would never be called, not a
major issue, i'm going to assume that the JS method never fails (else
it would have an error handler).

I'm not entirely sure yet how to implement this with AsyncCallback.
For example, for the getSelf method of google.gdata.Entry (http://
code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html#getSelf)
i could do the following:
JS
function getSelf(<function(Object)> continuation, <function(Error)>
opt_errorHandler)

Java
public final native Entry getSelf(<function(Object)> continuation,
<function(Error)> opt_errorHandler)/*-{
//it gets difficult here
var cbw1 = { cb: continuation, call: function(o)
{ @this.cb.AsyncCallback::onSuccess(Ljava/lang/Object;)(o); } }
var cbw2 = { cb: opt_errorHandler, call: function(e)
{ @this.cb.AsyncCallback::onFailure(Lcustom/gdata/aux/FailureError;)
(e); } }
return this.getSelf(cbw1.call, cbw2.call);
}-*/

One unknown here on my part is the JNI notation for generics (http://
java.sun.com/j2se/1.4.2/docs/guide/jni/spec/types.html#wp16432), i'm
assuming that it's no different than non-generics and that we still
use "L fully-qualified-class ;".

Also in my JSNI code above for getSelf, i see that it would fail if
the original GData JS Entry.getSelf implementation does the following:
Entry.prototype.getSelf = function(continuation, opt_errorHandler){
this.success_cb = continuation;
this.failure_cb = opt_errorHandler;
//do something
}

Because then then the "cb" property that the "call" method references
won't be available. Maybe there's some neat JS trick that i can use to
prevent this but i don't know what it is, unless i store the success
and failure callbacks in global vars (which doesn't excite me).

Bobby

On Apr 19, 8:26 pm, Thomas Broyer <t.bro...@gmail.com> wrote:
> On 20 avr, 01:47, Bobby <bobbysoa...@gmail.com> wrote:
>
>
>
> > While i have your attention, on #5 and constants Vs enumerations - I
> > won't know the value of the constants at the time of generating the
> > wrapper (i think that even if i did i would still rather not have them
> > hard coded in the wrapper class). This means that i can't have JS
> > constants become static final fields in the Java class. I guess in the
> > worst case i could have a single JSNI method for retrieving the value
> > of a given constant, given the name, or one JSNI method per constant,
> > but Enums would be much more developer friendly.
>
> There has been some news recently about enums in GWT:http://code.google.com/p/google-web-toolkit/wiki/EnumOptimizationshttp://timepedia.blogspot.com/2009/04/gwts-type-system-is-more-powerf...
> (FYI, the GData Java Client use constants for these:http://code.google.com/intl/fr-FR/apis/gdata/javadoc/com/google/gdata...
> )
>
> An example using an enum:http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/l...http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/l...
>
> An example using "just constants":http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/l...
>
> > For #6 and Callbacks, i agree that interfaces are much more developer
> > friendly, but these would be difficult to dynamically generate (for
> > example, what would the generator name the interface, whould it reuse
> > interfaces across different methods?).
>
> After a quick scan of the GData Java client API, there doesn't seem to
> be much callbacks, so in the JS API most if not all callbacks should
> be due to its async nature, thus are likely to be a pair of (<function
> (Object)> continuation, <function(Error)> opt_errorHandler), which
> could be mapped to AsyncCallback or a few AsyncCallback derivatives
> (and a hand-coded specialized exception to wrap the Error object).
>
> > I don't have to auto-generate
> > 100% of the code, in the end there may always be some manual editing,
> > but it's a pity.
> > Right now (without constants) 90% of the generated wrapper for
> > Google.GData compiles, the callbacks are the missing 10%.
>
> If AsyncCallback covers 90% of those 10%, it lefts only 1% or manual
> editing ;-)
>
> (FYI, GWT-in-the-AIR is entirely hand-written)- Hide quoted text -

Thomas Broyer

unread,
Apr 20, 2009, 10:14:02 AM4/20/09
to Google Web Toolkit

On 20 avr, 03:56, Bobby <bobbysoa...@gmail.com> wrote:
> Thomas, In your reply above you were asking if i shouldn't instead
> have:
> public final native String getAddress() /*-{ return this.address; }-
>
> Not really because the GData JS library uses getters/setters (which is
> nice) so the getAddress method exists on the JS side:http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Im.html#getA...

I'm not sure to understand why this "is nice" but, well, it seems to
be the way the GData API has been written, so...

> I wasn't aware that "return" wasn't necessary (though it makes sense),
> this is why i ask stuff.

Only when the Java method's return type is void!

> On constants vs enumerations, ok if constants are good enough for the
> Java GData library then they're good enough for me - it saves me the
> work of trying to plug the enumeration types into the method
> parameters and return values. I'm going to follow the same approach as
> in the following link that you provided:http://code.google.com/p/gwt-in-the-air/source/browse/trunk/src/net/l...

Note that this kind of initialization has an overhead: the class has a
"clinit", so even if you do not use the constants at all in your code,
there will be code to initialize them (won't be pruned by the compiler
because of the JSNI, which could have side effects).
I'll probably either move the constant fields into a Constants inner
class (Event.Constants.ACTIVATE instead of Event.ACTIVATE) or use
"true Java constants" (i.e. without JSNI), because the values for the
constants are clearly documented.

> AsyncCallback seems like a good fit, i counted three classes in the JS
> GData library (out of 238) that use callbacks:http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Feed.htmlhttp://code.google.com/apis/gdata/jsdoc/1.8/google/accounts/user.htmlhttp://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html
>
> The Feed and Entry classes always have a pair of callbacks for success
> and failure, the User class uses single onSuccess callbacks - the
> onFailure method of the AsyncCallback would never be called, not a
> major issue, i'm going to assume that the JS method never fails (else
> it would have an error handler).

How about using a com.google.gwt.user.client.Command instead?

> I'm not entirely sure yet how to implement this with AsyncCallback.
> For example, for the getSelf method of google.gdata.Entry (http://
> code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Entry.html#getSelf)
> i could do the following:
> JS
> function getSelf(<function(Object)> continuation, <function(Error)>
> opt_errorHandler)
>
> Java
> public final native Entry getSelf(<function(Object)> continuation,
> <function(Error)> opt_errorHandler)/*-{
>         //it gets difficult here
>         var cbw1 = { cb: continuation, call: function(o)
> { @this.cb.AsyncCallback::onSuccess(Ljava/lang/Object;)(o); } }
>         var cbw2 = { cb: opt_errorHandler, call: function(e)
> { @this.cb.AsyncCallback::onFailure(Lcustom/gdata/aux/FailureError;)
> (e); } }
>         return this.getSelf(cbw1.call, cbw2.call);
>
> }-*/

(I'm perplex about the return type... isn't it rather the type of
object passed to the continuation? looking at sample code and the doc,
it seems like a problem with the JSDoc; updateEntry for instance would
probably passe the Entry to the continuation, instead of returning an
Entry --calls are asynchronous and the doc says "Returns: the new
representation of the entry returned from the service.")

public final native void getSelf(AsyncCallback<Entry> callback) /*-{
this.getSelf(function(entry) {
@gdata.Utils::handleCallback(Lcom/google/gwt/user/client/rpc/
AsyncCallback;Ljava/lang/Object;)(callback, entry);
},
function(error) {
@gdata.Utils::handleError(Lcom/google/gwt/user/client/rpc/
AsyncCallback;Lcom/google/gwt/core/JavaScriptObject;)(callback,
error);
}
);
}-*/

with a class named Utils with the following static methods:
@SuppressWarning("unchecked")
private static void handleCallback(AsyncCallback cb, Object arg) {
// do the thing with UncaughtExceptionHandle, etc. resulting in:
// cb.onSuccess(arg);
}

@SuppressWarning("unchecked")
private static void handleError(AsyncCallback cb, JavaScriptObject
error) {
// same here.
}

Note that because the error in GData is a JavaScript Error object, you
don't have to use a custom exception, you can just use a
JavaScriptException:
cb.onFailure(new JavaScriptException(error));

> One unknown here on my part is the JNI notation for generics (http://
> java.sun.com/j2se/1.4.2/docs/guide/jni/spec/types.html#wp16432), i'm
> assuming that it's no different than non-generics and that we still
> use "L fully-qualified-class ;".

Generics are handle by type erasure in Java, so you have to use the
erasure type; use the Google Plugin for Eclipse, it provides
autocompletion facilities and will flag errors if any.

> Also in my JSNI code above for getSelf, i see that it would fail if
> the original GData JS Entry.getSelf implementation does the following:
> Entry.prototype.getSelf = function(continuation, opt_errorHandler){
>           this.success_cb = continuation;
>           this.failure_cb = opt_errorHandler;
>           //do something
>
> }
>
> Because then then the "cb" property that the "call" method references
> won't be available. Maybe there's some neat JS trick that i can use to
> prevent this but i don't know what it is, unless i store the success
> and failure callbacks in global vars (which doesn't excite me).

The pattern is simply:
var that = this;
this.method(function(a, b, c) {
that.@my.package.MyClass::onDone(III)(a, b, c);
});

Bobby

unread,
Apr 20, 2009, 12:38:19 PM4/20/09
to Google Web Toolkit, Thomas Broyer
Thomas,

The fact that the JS libraries implement getters and setters is "nice"
for me because i don't have to worry about creating the getters and
setters, i can just mirror what is already in JS so it's one less
thing to worry about (in this case i have to since there may be
additional logic inside the getters and setters).

Oops, the setters don't need to return anything, the returns were left
in there for no good reason, thanks for pointing that out.

I realize that your getConstant approach has an initialization
overhead but i'm going to overlook that so that i can get the
generated library to a point where i can test it and then come back
and revisit this. This will be more complex because the GData JS
implementation allows "namespaces" to be loaded dynamically as needed.

On the return type of the JS methods that receive callbacks, most
likely these methods return void, i think that's just the way the
JSDocs display - otherwise they would have to display that as
void updateEntry(<google.gdata.Entry function(Object)> continuation,
<google.gdata.Entry function(Error)> opt_errorHandler).
This type of ambiguity is why an 100% auto-generate is not going to
happen - in addition to this there are a couple of classes missing
from the JS Docs (i'll just fill those in from the GData Java docs).

I like the idea of using an intermediate class to handle the
callbacks, i think you mentioned this in your original reply and i
missed it.

If you're interested, and since you already put some time here i can
add you as a member of this project:
http://code.google.com/p/gdata-gwt-client/
This way you get some credit. This is a key library for GWT in my
opinion and it's missing - Google says they don't have plans to do
this right now so it's a good opportunity. I need this GWT library for
a separate project: http://code.google.com/p/gdbe/

Bobby
> > GData library (out of 238) that use callbacks:http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Feed.htmlhtt...
> });- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -

Thomas Broyer

unread,
Apr 20, 2009, 6:04:49 PM4/20/09
to Bobby, Google Web Toolkit
On Mon, Apr 20, 2009 at 6:38 PM, Bobby wrote:
>
> I realize that your getConstant approach has an initialization
> overhead but i'm going to overlook that so that i can get the
> generated library to a point where i can test it and then come back
> and revisit this. This will be more complex because the GData JS
> implementation allows "namespaces" to be loaded dynamically as needed.

Given that the protocol is clearly defined and documented, I wonder if
a "pure GWT" implementation wouldn't be better...
Well, eventually, that could be your "v2.0" ;-)

> On the return type of the JS methods that receive callbacks, most
> likely these methods return void, i think that's just the way the
> JSDocs display - otherwise they would have to display that as
> void updateEntry(<google.gdata.Entry function(Object)> continuation,
> <google.gdata.Entry function(Error)> opt_errorHandler).

Er, you probably mean void updateEntry(<void
function(google.gdata.Entry)> continuation, <void function(Error)>
opt_errorHandler)

> This type of ambiguity is why an 100% auto-generate is not going to
> happen - in addition to this there are a couple of classes missing
> from the JS Docs (i'll just fill those in from the GData Java docs).

Well, I don't know what you're generating from, but it could be as
easy as "if the method takes 2 arguments of type function, the second
one taking an Error argument, then convert them to an AsyncCallback<T>
where T is the method's documented return type, and make the method
actually have a void return type".

> I like the idea of using an intermediate class to handle the
> callbacks, i think you mentioned this in your original reply and i
> missed it.

Hmm, not quite sure what you're talking about...

> If you're interested, and since you already put some time here i can
> add you as a member of this project:
> http://code.google.com/p/gdata-gwt-client/
> This way you get some credit.

I'd rather wait to see some code ;-)
(and I have so many projects yet that I don't have time to update...)

> This is a key library for GWT in my
> opinion and it's missing - Google says they don't have plans to do
> this right now so it's a good opportunity.

Probably because they'd rather do it in GWT than as a GWT wrapper
around the JS API, which is a bit more work probably...
(and they'd have to have time to maintain it, etc.)

Anyway, good luck ;-)

--
Thomas Broyer

Bobby

unread,
Apr 20, 2009, 6:51:08 PM4/20/09
to Google Web Toolkit
The GData JS API is doing some fancy stuff to be able to POST data
across domains, etc, it's also fairly large (in number of classes) and
it's missing some large GData components (for Google Docs and
Spreadsheets). All of this i'm guessing is why Google doesn't have a
GWT library out for GData yet. I wouldn't want to code this manually
but i if i can automate it then it's ok.

> I'd rather wait to see some code ;-)
> (and I have so many projects yet that I don't have time to update...)

Oh right, no chance, it's now or never (or whenever you feel like up
to it, just let me know).

I'm counting on being able to auto-generate a decent wrapper without
much difficulty, if this becomes complex or beyond my means i'll just
let Google worry about it. This is why i want to test a rough version
of the wrapper ASAP.

Anyway thanks for all the pointers, i'll post more questions here as
they come up.

Bobby

Bobby

unread,
Apr 26, 2009, 11:43:46 PM4/26/09
to Google Web Toolkit
I finally got the GData library to compile inside a GWT 1.6 test app.
Now it's down to testing.

I'm considering auto generating a test app as well, otherwise i won't
be able to find out what's broken, otherwise i have to test each class
manually.

It looks good at this point but i'm antecipating plenty of headaches
in testing.

Bobby
> > Thomas Broyer- Hide quoted text -

Vitali Lovich

unread,
Apr 26, 2009, 11:55:24 PM4/26/09
to Google-We...@googlegroups.com
Couldn't arbitrary JS support be added using deferred binding?  Sure, you wouldn't be able to do code completion, but you could call arbitrary JS functions & variables with 0-overhead.  Might be a cool project to do (if Ray hasn't already done it :D).

Bobby

unread,
Apr 27, 2009, 2:21:49 AM4/27/09
to Google Web Toolkit
I would prefer having a GWT library for GData, it seems within reach.

Bobby
> > > - Show quoted text -- Hide quoted text -

Bobby

unread,
Apr 27, 2009, 2:58:23 AM4/27/09
to Google Web Toolkit
I just came across some interesting docs, this one in particular
covers almost all the questions i had in my original post (lots of
TBDs though):
http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis&t=DesigningAPIWrappers

Also, check out what's underneath the "large efforts" heading in the
wishlist page:
http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis&t=WishList

That's right, and here i am going it alone, you ought to be
ashamed. :)

Bobby

Bobby

unread,
May 3, 2009, 2:40:36 AM5/3/09
to Google Web Toolkit
I'm going over the following pages carefully:
http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis&t=Overview

Some GWT APIs, such as the Maps API, already have an implementation of
the AjaxLoader for loading Google JS libraries, so that's one less
thing to do.

Bobby

On Apr 27, 2:58 am, Bobby <bobbysoa...@gmail.com> wrote:
> I just came across some interesting docs, this one in particular
> covers almost all the questions i had in my original post (lots of
> TBDs though):http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis...
>
> Also, check out what's underneath the "large efforts" heading in the
> wishlist page:http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis...

Eric Ayers

unread,
May 3, 2009, 6:38:08 AM5/3/09
to Google-We...@googlegroups.com
Hi guys,

The AjaxLoader API will be put in public release soon.  I've made a release branch for it under subversion at http://gwt-google-apis.googlecode.com/svn/releases/ajaxloader/1.0

-Eric.
--
Eric Z. Ayers - GWT Team - Atlanta, GA USA
http://code.google.com/webtoolkit/

Bobby

unread,
May 3, 2009, 2:51:27 PM5/3/09
to Google Web Toolkit
Thanks Eric, it works for me. On a related topic, there's a namespace
in the GData API, google.accounts, that i think should be in its own
GWT module as well:
http://code.google.com/apis/gdata/jsdoc/1.8/google/accounts.html

It's used by GData to authenticate via AuthSub, but it's outside
GData.

Bobby

On May 3, 6:38 am, Eric Ayers <zun...@google.com> wrote:
> Hi guys,
> The AjaxLoader API will be put in public release soon.  I've made a release
> branch for it under subversion athttp://gwt-google-apis.googlecode.com/svn/releases/ajaxloader/1.0
>
> -Eric.
>
>
>
>
>
> On Sun, May 3, 2009 at 2:40 AM, Bobby <bobbysoa...@gmail.com> wrote:
>
> > I'm going over the following pages carefully:
>
> >http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis...
> Eric Z. Ayers - GWT Team - Atlanta, GA USAhttp://code.google.com/webtoolkit/- Hide quoted text -

Eric Ayers

unread,
May 3, 2009, 9:05:57 PM5/3/09
to Google-We...@googlegroups.com
I think you should make it a separate module, but at this point, I think it should remain under gdata for now.  I see other APIs use this namespace, but I will have to coordinate to see if it can truly be shared like AjaxLoader apis. 

Bobby

unread,
May 11, 2009, 3:17:41 AM5/11/09
to Google Web Toolkit
I'm very close, i've just compiled a GData JS example via the GData
GWT library - which retrieves a Calendar feed - and it worked.

Here are some of the implementation choices i've made so far:
- map all namespaces to be under com.google.gwt.gdata.client.*
- map all Object parameters to JavaScriptObject (some GData functions
receive generic JS objects for initialization purposes).
- implement JS classes as Overlay Types
- implement class constants as JSNI methods, for example:
public static native String REL_MESSAGE_TO() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_TO; }-*/;
- implement constructors as JSNI methods (since i'm using Overlay
Types), for example:
public static native Who construct() /*-{ return new
$wnd.google.gdata.Who(undefined); }-*/;
- generate overloads for methods that have optional parameters or
multi-type parameters in JS, for example:
public final native void setValueString(String valueString) /*-
{ this.setValueString(valueString); }-*/;
public final native void setValueString() /*-{ this.setValueString
(undefined); }-*/;
- implement continuation callbacks (non success/failure) as Runnable,
for example:
public static final native boolean getInfo(Runnable callback) /*-
{ return $wnd.google.accounts.user.getInfo(function()
{ callback.@java.lang.Runnable::run()(); }); }-*/;
- implement success/failure callbacks as AsyncCallback<T>, for
example:
public final native CalendarAclFeed getAclFeed(String uri,
AsyncCallback<CalendarAclFeed> callback) /*-{
return this.getAclFeed(uri, function(result)
{ @com.google.gwt.gdata.client.impl.Utils::handleSuccessCallback(Lcom/
google/gwt/user/client/rpc/AsyncCallback;Ljava/lang/Object;)(callback,
result); }, function(error)
{ @com.google.gwt.gdata.client.impl.Utils::handleFailureCallback(Lcom/
google/gwt/user/client/rpc/AsyncCallback;Ljava/lang/String;)(callback,
error); });
}-*/;
- ignore all instance fields, since GData implements getters and
setters.
- use the existing AjaxLoader to loading the JS libraries.

Pending testing. Adding overloads has been interesting, for a given
method with n optional parameters there are 2^n overloads to be added
- plus some JS methods have multi-type parameters so those need to be
defined as well.

Here's a class from the GWT GData library (corresponds to
http://code.google.com/apis/gdata/jsdoc/1.8/google/gdata/Who.html):

package com.google.gwt.gdata.client;
import com.google.gwt.gdata.client.EntryLink;
import com.google.gwt.gdata.client.AttendeeType;
import com.google.gwt.gdata.client.AttendeeStatus;
import com.google.gwt.core.client.JavaScriptObject;

public class Who extends com.google.gwt.core.client.JavaScriptObject {
public static native String REL_EVENT_ATTENDEE() /*-{ return
$wnd.google.gdata.Who.REL_EVENT_ATTENDEE; }-*/;
public static native String REL_EVENT_ORGANIZER() /*-{ return
$wnd.google.gdata.Who.REL_EVENT_ORGANIZER; }-*/;
public static native String REL_EVENT_PERFORMER() /*-{ return
$wnd.google.gdata.Who.REL_EVENT_PERFORMER; }-*/;
public static native String REL_EVENT_SPEAKER() /*-{ return
$wnd.google.gdata.Who.REL_EVENT_SPEAKER; }-*/;
public static native String REL_MESSAGE_BCC() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_BCC; }-*/;
public static native String REL_MESSAGE_CC() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_CC; }-*/;
public static native String REL_MESSAGE_FROM() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_FROM; }-*/;
public static native String REL_MESSAGE_REPLY_TO() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_REPLY_TO; }-*/;
public static native String REL_MESSAGE_TO() /*-{ return
$wnd.google.gdata.Who.REL_MESSAGE_TO; }-*/;
public static native String REL_TASK_ASSIGNED_TO() /*-{ return
$wnd.google.gdata.Who.REL_TASK_ASSIGNED_TO; }-*/;

protected Who() { }

public static native Who construct(JavaScriptObject opt_params) /*-
{ return new $wnd.google.gdata.Who(opt_params); }-*/;
public static native Who construct() /*-{ return new
$wnd.google.gdata.Who(undefined); }-*/;

public final native AttendeeStatus getAttendeeStatus() /*-{ return
this.getAttendeeStatus(); }-*/;
public final native AttendeeType getAttendeeType() /*-{ return
this.getAttendeeType(); }-*/;
public final native String getEmail() /*-{ return this.getEmail(); }-
*/;
public final native EntryLink getEntryLink() /*-{ return
this.getEntryLink(); }-*/;
public final native String getRel() /*-{ return this.getRel(); }-*/;
public final native String getValueString() /*-{ return
this.getValueString(); }-*/;
public final native void setAttendeeStatus(JavaScriptObject
attendeeStatus) /*-{ this.setAttendeeStatus(attendeeStatus); }-*/;
public final native void setAttendeeStatus() /*-
{ this.setAttendeeStatus(undefined); }-*/;
public final native void setAttendeeStatus(AttendeeStatus
attendeeStatus) /*-{ this.setAttendeeStatus(attendeeStatus); }-*/;
public final native void setAttendeeType(JavaScriptObject
attendeeType) /*-{ this.setAttendeeType(attendeeType); }-*/;
public final native void setAttendeeType() /*-{ this.setAttendeeType
(undefined); }-*/;
public final native void setAttendeeType(AttendeeType attendeeType) /
*-{ this.setAttendeeType(attendeeType); }-*/;
public final native void setEmail(String email) /*-{ this.setEmail
(email); }-*/;
public final native void setEmail() /*-{ this.setEmail(undefined); }-
*/;
public final native void setEntryLink(JavaScriptObject entryLink) /*-
{ this.setEntryLink(entryLink); }-*/;
public final native void setEntryLink() /*-{ this.setEntryLink
(undefined); }-*/;
public final native void setEntryLink(EntryLink entryLink) /*-
{ this.setEntryLink(entryLink); }-*/;
public final native void setRel(String rel) /*-{ this.setRel(rel); }-
*/;
public final native void setRel() /*-{ this.setRel(undefined); }-*/;
public final native void setValueString(String valueString) /*-
{ this.setValueString(valueString); }-*/;
public final native void setValueString() /*-{ this.setValueString
(undefined); }-*/;
}

Bobby
> > code.google.com/webtoolkit/- Hide quoted text -

Eric Ayers

unread,
May 18, 2009, 3:30:20 PM5/18/09
to Google-We...@googlegroups.com
Hi Bobby,

Thanks for the update, here is some feedback inline. Sorry for the
delay, I was out last week.

On Mon, May 11, 2009 at 3:17 AM, Bobby <bobby...@gmail.com> wrote:
>
> I'm very close, i've just compiled a GData JS example via the GData
> GWT library - which retrieves a Calendar feed - and it worked.
>
> Here are some of the implementation choices i've made so far:
> - map all namespaces to be under com.google.gwt.gdata.client.*
> - map all Object parameters to JavaScriptObject (some GData functions
> receive generic JS objects for initialization purposes).
> - implement JS classes as Overlay Types
> - implement class constants as JSNI methods, for example:
>  public static native String REL_MESSAGE_TO() /*-{ return
> $wnd.google.gdata.Who.REL_MESSAGE_TO; }-*/;
> - implement constructors as JSNI methods (since i'm using Overlay
> Types), for example:
>  public static native Who construct() /*-{ return new
> $wnd.google.gdata.Who(undefined); }-*/;

In the gwt-google-apis, I have been naming these factory methods
newInstance() or getInstance() for constructing singletons. This
comes from convention in the JRE and Joshua Bloch's "Effective Java".

> - generate overloads for methods that have optional parameters or
> multi-type parameters in JS, for example:
>  public final native void setValueString(String valueString) /*-
> { this.setValueString(valueString); }-*/;
>  public final native void setValueString() /*-{ this.setValueString
> (undefined); }-*/;
> - implement continuation callbacks (non success/failure) as Runnable,
> for example:
>  public static final native boolean getInfo(Runnable callback) /*-
> { return $wnd.google.accounts.user.getInfo(function()
> { callback.@java.lang.Runnable::run()(); }); }-*/;

This is good, but in order to display exceptions in Hosted mode, a
more complex pattern is needed. Essentially, you need to call a
special handler for exceptions in hosted mode. A particularly nice
implementation of this is the Handler class in gwt-visualization which
uses the ExceptionHelper class in the ajaxloader package.

http://code.google.com/p/gwt-google-apis/source/browse/releases/visualization/1.0/visualization/src/com/google/gwt/visualization/client/events/Handler.java
http://code.google.com/p/gwt-google-apis/source/browse/releases/ajaxloader/1.0/ajaxloader/src/com/google/gwt/ajaxloader/client/ExceptionHelper.java

I usually pull the ajaxloader class into the other gwt-google-api
projects using an svn:externals property if you haven't done that
already.

> - implement success/failure callbacks as AsyncCallback<T>, for
> example:
>  public final native CalendarAclFeed getAclFeed(String uri,
> AsyncCallback<CalendarAclFeed> callback) /*-{
>       return this.getAclFeed(uri, function(result)
> { @com.google.gwt.gdata.client.impl.Utils::handleSuccessCallback(Lcom/
> google/gwt/user/client/rpc/AsyncCallback;Ljava/lang/Object;)(callback,
> result); }, function(error)
> { @com.google.gwt.gdata.client.impl.Utils::handleFailureCallback(Lcom/
> google/gwt/user/client/rpc/AsyncCallback;Ljava/lang/String;)(callback,
> error); });
> }-*/;

Same comment here - if you don't add the UncaughtExceptionHandler
stuff, hosted mode will miss exceptions that occur in the callback.
I believe that passing 'undefined' as a parameter is the same as
passing no parameters at all. In general, making the JavaScript less
verbose will make the resulting compiled code smaller to download.
Every bit helps!

Bobby

unread,
May 20, 2009, 5:21:24 PM5/20/09
to Google Web Toolkit
Thanks for the tips Eric.

- I noticed that newInstance was used in Google Maps so i'm adopted
the same convention.

- I see what you mean about exception handling. I'll make use of your
ExceptionHelper for Runnables. For the AsyncCallbacks, i'll try to
mirror your ExceptionHelper implementation.

- When generating the overloads i plug "undefined" in place of omitted
optional parameters. Methods with only one parameter were causing the
single "undefined" parameter you pointed out, this will be gone after
polishing.

I have another batch of questions/comments coming up - there's one
class in GData, the base class for all service classes, which requires
some thought since it has methods that may receive constructors (for
example GetFeed, which receives the constructor of the feed to be
returned). How this class is implemented has some implications on the
classes that extend it. I'll have the auto-generated GWT library up
sometime next week, this way i'll be able to link to the GWT and JS
classes and hopefully get some more feedback on the implementation -
not so much on the JSNI code but on the architecture/structure of the
library.

I'm also attempting to auto-generating base Unit tests for each class
- most classes are data classes, so Unit tests are straightforward
enough (e.g. call each setter, call the corresponding getter, check
that the gotten value is the set value). The service classes
themselves, which retrieve and update data in the various systems are
more difficult, i don't have a plan for those, there will probably be
some manual labor but it's not the end of the world if it comes to
that.

Bobby
> > { callba...@java.lang.Runnable::run()(); }); }-*/;
>
> This is good, but in order to display exceptions in Hosted mode, a
> more complex pattern is needed.  Essentially, you need to call a
> special handler for exceptions in hosted mode.  A particularly nice
> implementation of this is the Handler class in gwt-visualization which
> uses the ExceptionHelper class in the ajaxloader package.
>
> http://code.google.com/p/gwt-google-apis/source/browse/releases/visua...http://code.google.com/p/gwt-google-apis/source/browse/releases/ajaxl...
> ...
>
> read more »- Hide quoted text -

Bobby

unread,
May 25, 2009, 11:32:56 PM5/25/09
to Google Web Toolkit
Eric, what is the svn:externals read-only path for the AjaxLoader
source? I tried the following with no success (probably because the
link is not read-only and i don't have checkout access):

ajaxloader http://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/src/

Bobby
> >http://code.google.com/p/gwt-google-apis/source/browse/releases/visua......

Bobby

unread,
May 26, 2009, 12:07:05 AM5/26/09
to Google Web Toolkit
This is the gwt-gdata project http://code.google.com/p/gwt-gdata/. The
code auto-generated from the JS Docs is available:
http://code.google.com/p/gwt-gdata/source/browse/

I uploaded that code mostly for the sake of pointing to it and getting
feedback, there are corrections to be made - though it does compile
and of the unit tests (1 per class) most succeed (187/239) though
these unit tests aren't that involved. It should be a good starting
point.

I still need to plug the ExceptionHelper and ArrayHelper from the
AjaxLoader (have a few questions on this one) into the code and
extract the parameter and return value comments from the JS Docs.

Currently i'm not handling Arrays properly and this came out in the
unit tests. For example in the RecurrenceExceptionEntry (http://
code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/google/
gwt/gdata/client/RecurrenceExceptionEntry.java), the getWhen,
getWhere, getWho, setWhen, setWhere, setWho have return and receive
Java arrays - needs to use JsArray<T> instead (through the
ArrayHelper).

I should probably create a new thread for discussing the GWT-GData
project in specific.

Bobby

On May 25, 11:32 pm, Bobby <bobbysoa...@gmail.com> wrote:
> Eric, what is the svn:externals read-only path for the AjaxLoader
> source? I tried the following with no success (probably because the
> link is not read-only and i don't have checkout access):
>
> ajaxloaderhttp://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/src/

Eric Ayers

unread,
May 26, 2009, 8:56:35 AM5/26/09
to Google-We...@googlegroups.com
The read-only link starts with http, but there may be an error in the URL:

http://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader/src/

(2 instances of the string ajaxloader in the path)

-Eric.

Thomas Broyer

unread,
May 26, 2009, 9:01:54 AM5/26/09
to Google Web Toolkit


On 26 mai, 14:56, Eric Ayers <zun...@google.com> wrote:
> The read-only link starts with http, but there may be an error in the URL:
>
> http://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader...
>
> (2 instances of the string ajaxloader in the path)

...and given where Bobby sets his svn:external, it should even be
http://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader/src/com/google/gwt/ajaxloader/

Bobby

unread,
May 29, 2009, 2:03:31 AM5/29/09
to Google Web Toolkit
Thanks that was it.

Bobby
> ...and given where Bobby sets his svn:external, it should even behttp://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader...

Bobby

unread,
May 30, 2009, 2:03:59 AM5/30/09
to Google Web Toolkit
I'm seeing some weird behavior whenever java.util.Date is used. The
following DateTime class in GData wraps around a date:
http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/google/gwt/gdata/client/DateTime.java

The newInstance method receives a java.util.Date.:

public static native DateTime newInstance(Date date, boolean
dateOnly) /*-{
return new $wnd.google.gdata.DateTime(
date,
dateOnly
);
}-*/;

Whenever i call this method it fails. If i replace it with the
following, then it works:

public static native DateTime newInstance(Date date, boolean
dateOnly) /*-{
return new $wnd.google.gdata.DateTime(
new Date(), //pass static JS date instead
dateOnly
);
}-*/;

So the date object passed in from Java causes a failure whereas a
regular JS date doesn't. I looked at the Date parameter passed in from
Java and it looked like a regular JS date - when printed, a regular
date string is displayed.
In web mode jUnit hangs on newInstance(new Date(), true/false) because
a JS exception occurs. In hosted mode the following exception is
thrown:

[WARN] Malformed JSNI reference 'getFullYear'; expect subsequent
failures
java.lang.NoSuchFieldError: getFullYear
at com.google.gwt.dev.shell.CompilingClassLoader
$DispatchClassInfoOracle.getDispId(CompilingClassLoader.java:119)
at com.google.gwt.dev.shell.CompilingClassLoader.getDispId
(CompilingClassLoader.java:531)
at com.google.gwt.dev.shell.ie.IDispatchProxy.getIDsOfNames
(IDispatchProxy.java:124)
at com.google.gwt.dev.shell.ie.IDispatchImpl.GetIDsOfNames
(IDispatchImpl.java:273)
at com.google.gwt.dev.shell.ie.IDispatchImpl.method5
(IDispatchImpl.java:189)
at org.eclipse.swt.internal.ole.win32.COMObject.callback5
(COMObject.java:108)
at org.eclipse.swt.internal.ole.win32.COM.VtblCall(Native Method)
at org.eclipse.swt.internal.ole.win32.IDispatch.Invoke(IDispatch.java:
64)
at org.eclipse.swt.ole.win32.OleAutomation.invoke(OleAutomation.java:
493)
at org.eclipse.swt.ole.win32.OleAutomation.invoke(OleAutomation.java:
417)
at com.google.gwt.dev.shell.ie.ModuleSpaceIE6.doInvokeOnWindow
(ModuleSpaceIE6.java:67)
at com.google.gwt.dev.shell.ie.ModuleSpaceIE6.doInvoke
(ModuleSpaceIE6.java:152)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:
447)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid
(ModuleSpace.java:248)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid
(JavaScriptHost.java:107)
at com.google.gwt.gdata.client.app.Edited$.setValue$(Edited.java)
at com.google.gwt.gdata.client.app.EditedTest.testProperties
(EditedTest.java:42)
at com.google.gwt.gdata.client.app.__EditedTest_unitTestImpl.doRunTest
(transient source for
com.google.gwt.gdata.client.app.__EditedTest_unitTestImpl:7)
at junit.framework.TestCase.runTest(TestCase.java:62)
at com.google.gwt.junit.client.GWTTestCase.runBare(GWTTestCase.java:
178)
at com.google.gwt.junit.client.GWTTestCase.__doRunTest
(GWTTestCase.java:116)
at com.google.gwt.junit.client.impl.GWTRunner.runTest(GWTRunner.java:
188)
at com.google.gwt.junit.client.impl.GWTRunner.doRunTest
(GWTRunner.java:163)
at com.google.gwt.junit.client.impl.GWTRunner.access$3(GWTRunner.java:
157)
at com.google.gwt.junit.client.impl.GWTRunner
$JUnitHostListener.onSuccess(GWTRunner.java:61)
at com.google.gwt.junit.client.impl.GWTRunner
$JUnitHostListener.onSuccess(GWTRunner.java:1)
at
com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.onResponseReceived
(RequestCallbackAdapter.java:215)
at com.google.gwt.http.client.Request.fireOnResponseReceivedImpl
(Request.java:254)
at com.google.gwt.http.client.Request.fireOnResponseReceivedAndCatch
(Request.java:226)
at com.google.gwt.http.client.Request.fireOnResponseReceived
(Request.java:217)
at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:
103)
at com.google.gwt.dev.shell.ie.IDispatchImpl.callMethod
(IDispatchImpl.java:126)
at com.google.gwt.dev.shell.ie.IDispatchProxy.invoke
(IDispatchProxy.java:155)
at com.google.gwt.dev.shell.ie.IDispatchImpl.Invoke
(IDispatchImpl.java:294)
at com.google.gwt.dev.shell.ie.IDispatchImpl.method6
(IDispatchImpl.java:194)
at org.eclipse.swt.internal.ole.win32.COMObject.callback6
(COMObject.java:117)
at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:1925)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2966)
at com.google.gwt.dev.GWTShell.pumpEventLoop(GWTShell.java:720)
at com.google.gwt.junit.JUnitShell.runTestImpl(JUnitShell.java:654)
at com.google.gwt.junit.JUnitShell.runTest(JUnitShell.java:150)
at com.google.gwt.junit.client.GWTTestCase.runTest(GWTTestCase.java:
219)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at com.google.gwt.junit.client.GWTTestCase.run(GWTTestCase.java:132)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at
org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run
(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run
(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests
(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests
(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run
(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main
(RemoteTestRunner.java:196)

Any idea why this might be happening? Is it IE6 related?

Bobby
> > ...and given where Bobby sets his svn:external, it should even behttp://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader...- Hide quoted text -

Eric Ayers

unread,
May 30, 2009, 5:04:12 PM5/30/09
to Google-We...@googlegroups.com
I don't think GWT does anything useful when you pass a Java Date
object into JSNI. You may want to pass the # of milliseconds since
1970 instead.

Bobby

unread,
May 30, 2009, 10:21:01 PM5/30/09
to Google Web Toolkit
I eliminated the Date errors by making use of a DateHelper:
http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/google/gwt/gdata/client/impl/DateHelper.java

Here's how i'm using it:
http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/google/gwt/gdata/client/DateTime.java

I convert Dates to milliseconds since 1970 before passing them between
Java and JS.

Bobby

On May 30, 5:04 pm, Eric Ayers <zun...@google.com> wrote:
> I don't think GWT does anything useful when you pass a Java Date
> object into JSNI.  You may want to pass the # of milliseconds since
> 1970 instead.
>
>
>
>
>
> On Sat, May 30, 2009 at 2:03 AM, Bobby <bobbysoa...@gmail.com> wrote:
>
> > I'm seeing some weird behavior whenever java.util.Date is used. The
> > following DateTime class in GData wraps around a date:
> >http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/...
> > com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.onResponseReceiv­ed
> >> > ...and given where Bobby sets his svn:external, it should even behttp://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader...Hide quoted text -
>
> >> - Show quoted text -
>
> --
> Eric Z. Ayers - GWT Team - Atlanta, GA USAhttp://code.google.com/webtoolkit/- Hide quoted text -

Bobby

unread,
Jun 6, 2009, 10:45:11 PM6/6/09
to Google Web Toolkit
The GoogleAccounts module is working well and is pretty close to what
it needs to be:
http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/google/gwt/accounts

I was able to create jUnit test cases that impersonate user
authentication - the GData JS API AuthSub implementation performs
authentication by redirecting to a Google Accounts page, performing
auth and then redirecting back to the referring URL, passing along a
session token which gets stored in a cookie. To make the
authentication work i am setting the cookie directly which has the
same effect but allows the jUnit tests to work smoothly:
http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/test/com/google/accounts/client/UserTest.java

Now i can write unit tests for the services which read/write data with
a test account.

I'm debating whether i should split the GWT-Gdata module into multiple
sub modules. For example, instead of having one large GWT module at
com.google.gwt.gdata, have com.google.gwt.gdata be a base module
inherited by specialized modules such as:

com.google.gwt.gdata.calendar
com.google.gwt.gdata.blogger
com.google.gwt.gdata.contacts
com.google.gwt.gdata.finance
...etc

The reason is that, from my experience, you end up using GData to
interact with either Calendar or Documents for example, rather than
all of the GData systems, so it seems more natural to have a module
per GData system.

Bobby




On May 30, 10:21 pm, Bobby <bobbysoa...@gmail.com> wrote:
> I eliminated the Date errors by making use of a DateHelper:http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/...
>
> Here's how i'm using it:http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/...
> > >> > ...and given where Bobby sets his svn:external, it should even behttp://gwt-google-apis.googlecode.com/svn/trunk/ajaxloader/ajaxloader...quoted text -
>
> > >> - Show quoted text -
>
> > --
> > Eric Z. Ayers - GWT Team - Atlanta, GA USAhttp://code.google.com/webtoolkit/-Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -

Eric Ayers

unread,
Jun 7, 2009, 7:20:47 AM6/7/09
to Google-We...@googlegroups.com
Sounds like you are making good progress.
In the Gears API, we ran into a similar issue. Should we break out
the Gears components into separate modules?

In that case we decided that it was a burden on the user to have to
find and import the correct module. GWT does dead code stripping, so
there is no penalty at runtime for including parts of the API you
don't use. We put everything under one com.google.gwt.gears.client
package in the end.

In the GData case, I could see that developers are less likely to use
features from across multiple packages, so I could go either way, but
as far as runtime performance goes, there is no difference either way.
As far as convenience goes, having everything under one module makes
the setting up of your project's module easier.

Bobby

unread,
Jun 11, 2009, 2:58:28 AM6/11/09
to Google Web Toolkit
In that case i'll leave it as a single module.

The cookie insert approach to getting around authentication ended up
in a little headache because i forgot that GData requires an image to
be present on the page (loaded from the same domain as the page). So,
after forcing the cookie, the jUnit test case was acting as if logged
on but was failing when i called any service, because no image was
present. No error was being thrown in jUnit so i was in the dark for a
while, but after some fiddling i got it. What a relief!

I registered gwt....@gmail.com and successfully got a jUnit test
case to grab events grom GData calendar for that account. Now it's a
matter of doing the same thing for the other services.

Bobby

On Jun 7, 7:20 am, Eric Ayers <zun...@google.com> wrote:
> Sounds like you are making good progress.
>
>
>
> On Sat, Jun 6, 2009 at 10:45 PM, Bobby <bobbysoa...@gmail.com> wrote:
>
> > The GoogleAccounts module is working well and is pretty close to what
> > it needs to be:
> >http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/...
>
> > I was able to create jUnit test cases that impersonate user
> > authentication - the GData JS API AuthSub implementation performs
> > authentication by redirecting to a Google Accounts page, performing
> > auth and then redirecting back to the referring URL, passing along a
> > session token which gets stored in a cookie. To make the
> > authentication work i am setting the cookie directly which has the
> > same effect but allows the jUnit tests to work smoothly:
> >http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/test/com...
> ...
>
> read more »

Bobby

unread,
Jun 12, 2009, 1:46:55 PM6/12/09
to Google Web Toolkit
Ok, so time to look at class structure. In the JS API we have for
example:

com.google.gwt.gdata.client.calendar.CalendarFeed
com.google.gwt.gdata.client.Feed
com.google.gwt.gdata.client.atom.Feed

We won't be able to implement this structure with overlay types
because all methods are final, so for example CalendarFeed can't
override methods of its parent feed classes - it does need to override
methods to specialize the parameter and return types.

Most of the classes in the following namespaces are only used
internally.
com.google.gwt.gdata.client
com.google.gwt.gdata.client.atom

The approach seems to be to not have any class in those namespaces
used directly. For example, the Calendar namespace does not use
com.google.gwt.gdata.client.Who, instead it specializes that class as
com.google.gwt.gdata.client.calendar.CalendarWho and uses that.

So i have the following options:
1. leave the parent classes around, but remove any methods implemented
by child classes (this leaves polymorphism in place, but it's not of
much use, since these classes will be pretty much empty).
2. convert the parent classes to interfaces (this gives us useful
polymorphism)
3. remove these parent classes from the GWT API.

Option 1 is not very useful.
Option 2 works the best but perhaps adds too many interfaces.
Option 3 removes all of these internal classes, which gets rid of
polymorphism. With this approach, the GWT library would just have the
"leaves" of the GData API's class tree, which would result in a very
thin interface.

I'm leaning towards Option 2 at this time.

Bobby

On Jun 6, 10:45 pm, Bobby <bobbysoa...@gmail.com> wrote:
> The GoogleAccounts module is working well and is pretty close to what
> it needs to be:http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/src/com/...
>
> I was able to create jUnit test cases that impersonate user
> authentication - the GData JS API AuthSub implementation performs
> authentication by redirecting to a Google Accounts page, performing
> auth and then redirecting back to the referring URL, passing along a
> session token which gets stored in a cookie. To make the
> authentication work i am setting the cookie directly which has the
> same effect but allows the jUnit tests to work smoothly:http://code.google.com/p/gwt-gdata/source/browse/trunk/gdata/test/com...
> ...
>
> read more »- Hide quoted text -

Bobby

unread,
Jun 14, 2009, 2:28:29 AM6/14/09
to Google Web Toolkit
A few classes from the "internal" namespaces are used directly:
Link
FeedLink
DateTime
Money
PostalAddress
PhoneNumber
Organization
Im
ExtendedProperty
Email
Deleted
Text
Where
Category

So if i were to convert those classes to interfaces, i would have to
define specialized versions, which i'd rather not. An option is to
leave all classes alone and just add a bunch of interfaces, one per
class. So for example the following classes:
com.google.gwt.gdata.client.Feed
com.google.gwt.gdata.client.atom.Feed

Would implement the following interfaces respectively:
com.google.gwt.gdata.client.impl.IFeed
com.google.gwt.gdata.client.impl.atom.IFeed

Where the second interface extends the first, etc.

Since this can be added at any time, initially i'm going to keep the
API flat without any inheritance or interfaces, so i'll have each
class implement all of its methods, including those "inherited" from
parent classes. Personally i think that to do this right, the GWT
GData library should be built entirely with GWT rather than be
overlayed on top of the JS API, which is a huge project. To take it
one step at a time here's my plan:

1. Build GWT-GData on top of JS API without class inheritance.
2. Add "inheritance" via interfaces.
3. Add the service namespaces that are missing from the JS API (e.g.
Documents, YouTube, etc).
4. Remove the JS API and provide GWT implementation (as needed).

Bobby
> ...
>
> read more »

Bobby

unread,
Jun 14, 2009, 6:53:58 PM6/14/09
to Google Web Toolkit
A few more comments. There's a new version of the GData JS API (1.10)
which is a little larger - luckily i should be able to point the code
generator to the new docs and be up to speed. Also, i had a closer
look at the Java, Python and .NET versions and they're all very out of
sync with eachother.

The JS version seems to be the more extensive version (comparing for
example the number of classes within the Calendar namespace), even
though it's still missing a few namespaces, which tells me that it is
perhaps more active than the others. So the best i can do is try to
keep the GWT version as close to the JS version as possible and
completely ignore the Java version, which is quite different at this
point.

Bobby
> ...
>
> read more »

Bobby

unread,
Jun 14, 2009, 10:59:40 PM6/14/09
to Google Web Toolkit
I may be able to leave the inheritance in place without having
problems with overrides by just adding generics. The Feed and Entry
classes are the ones that are specialized in the API. The Java API has
the Feed and Entry classes as generics, for example:
http://code.google.com/apis/gdata/javadoc/com/google/gdata/data/calendar/CalendarEventFeed.html

The implementation of the base feed class would look like:
public class Feed <F extends Feed, E extends Entry> extends
JavaScriptObject {
...
}

If there are no issues in GWT this should be good.

Bobby
> ...
>
> read more »

Bobby

unread,
Jun 15, 2009, 2:53:09 AM6/15/09
to Google Web Toolkit
I ended up updating the following classes to generics:
1. com.google.gwt.gdata.client.atom.Feed
2. com.google.gwt.gdata.client.Feed
3. com.google.gwt.gdata.client.EventFeed

The implementation is, respectively:
1. public class Feed<E extends Entry> extends JavaScriptObject
2. public class Feed<E extends Entry> extends
com.google.gwt.gdata.client.atom.Feed<E>
3. public class EventFeed<E extends EventEntry> extends
com.google.gwt.gdata.client.Feed<E>

The remaining Feed classes then extend one of these base Feed classes.
For example CalendarEventFeed:
public class CalendarEventFeed extends EventFeed<CalendarEventEntry>

The good news is that there doesn't seem to be a need to override
parent class methods any longer but time will tell, which means the
class hierarchy stays the same, and the generics are alot neater.

I also pointed the generator to the latest JS API version 1.10 and
there were no issues. Right now it's looking pretty good, so it's back
to testing.

Bobby

On Jun 14, 10:59 pm, Bobby <bobbysoa...@gmail.com> wrote:
> I may be able to leave the inheritance in place without having
> problems with overrides by just adding generics. The Feed and Entry
> classes are the ones that are specialized in the API. The Java API has
> the Feed and Entry classes as generics, for example:http://code.google.com/apis/gdata/javadoc/com/google/gdata/data/calen...
> ...
>
> read more »

Bobby

unread,
Jun 22, 2009, 5:59:32 PM6/22/09
to Google Web Toolkit
One note about arrays. If a method in the API receives or returns an
array, i currently make use of the JsArray class, which can go travel
between JS and Java. I would prefer exposing these methods as
receiving and returning actual arrays rather than JsArray, only
because it's more generic (functionally there's little difference). I
could make use of an array helper class that would convert a JsArray
back and forth between a standard array, but if this will add some
overhead (such as having to iterate through the array members) then
it's probably not worth it. Any suggestions on this?

I expect to have a beta version of GWT-GData available for testing in
less than 2 weeks, barring any surprises, since it's looking fairly
good.

Bobby
> ...
>
> read more »

Thomas Broyer

unread,
Jun 23, 2009, 5:56:16 AM6/23/09
to Google Web Toolkit


On 22 juin, 23:59, Bobby <bobbysoa...@gmail.com> wrote:
> One note about arrays. If a method in the API receives or returns an
> array, i currently make use of the JsArray class, which can go travel
> between JS and Java. I would prefer exposing these methods as
> receiving and returning actual arrays rather than JsArray, only
> because it's more generic (functionally there's little difference).

Little but not negligible: a JsArray has a varying length.

> I
> could make use of an array helper class that would convert a JsArray
> back and forth between a standard array, but if this will add some
> overhead (such as having to iterate through the array members) then
> it's probably not worth it. Any suggestions on this?

It would add overhead only in Hosted Mode, as you can use a
"reinterpretCast" in Web Mode with no overhead at all. It's been
discussed several times on the list and you can find an example
(actually, a library) at http://code.google.com/p/gwt-in-the-air (in
the JsCollections module)

Bobby

unread,
Jun 23, 2009, 11:18:40 PM6/23/09
to Google Web Toolkit
Nice. Is the JsCollections module your own or are you referencing it
externally from somewhere? I'd like to add it via svn:externals.

Bobby

Thomas Broyer

unread,
Jun 24, 2009, 5:17:00 AM6/24/09
to Google Web Toolkit


On 24 juin, 05:18, Bobby <bobbysoa...@gmail.com> wrote:
> Nice. Is the JsCollections module your own or are you referencing it
> externally from somewhere? I'd like to add it via svn:externals.

It is my own, under Apache License 2.0 (same as GWT). You'll find a
gwt-jscollections.jar in the ZIP from the Downloads tab, containing
only the JsCollections module. It hasn't changed on SVN since then,
and it probably won't change unless it has a bug. So I'd rather
recommend using the JAR instead of svn:externals.

Bobby

unread,
Jun 25, 2009, 2:32:13 AM6/25/09
to Google Web Toolkit
Actually, i've just noticed that the ArrayHelper in the AjaxLoader
module provides the same functionality. Question though, when calling
the fromArray() method from within a JSNI method, what's the parameter
signature that should be used? I'm not having any luck with fromArray
(Lcom/google/gwt/core/client/JavaScriptObject;).

I want to transform the following:
public final native void setProperties(JsArray<Property> properties) /
*-{
this.setProperties(
properties
);
}-*/;

Into the following:

public final native void setProperties(Property[] properties) /*-{
this.setProperties(
@net.ltgt.gwt.jscollections.client.JsArrays::fromArray(Lcom/
google/gwt/core/client/JavaScriptObject;)(properties)
);
}-*/;

But GWT complains about not being able to find the method with that
signature. Also, why are the ellipsis used? Do they have a special
purpose in GWT?

Bobby

Thomas Broyer

unread,
Jun 25, 2009, 8:20:57 AM6/25/09
to Google Web Toolkit


On 25 juin, 08:32, Bobby <bobbysoa...@gmail.com> wrote:
> Actually, i've just noticed that the ArrayHelper in the AjaxLoader
> module provides the same functionality. Question though, when calling
> the fromArray() method from within a JSNI method, what's the parameter
> signature that should be used? I'm not having any luck with fromArray
> (Lcom/google/gwt/core/client/JavaScriptObject;).
>
> I want to transform the following:
> public final native void setProperties(JsArray<Property> properties) /
> *-{
>     this.setProperties(
>       properties
>     );
>
> }-*/;
>
> Into the following:
>
> public final native void setProperties(Property[] properties) /*-{
>     this.setProperties(
>       @net.ltgt.gwt.jscollections.client.JsArrays::fromArray(Lcom/
> google/gwt/core/client/JavaScriptObject;)(properties)
>     );
>
> }-*/;

I'd personally use an intermediate setProperty(JsArray<Property>) and
call the fromArray in pure Java.

> But GWT complains about not being able to find the method with that
> signature.

http://code.google.com/webtoolkit/doc/1.6/DevGuideCodingBasics.html#DevGuideJavaScriptNativeInterface
links to http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/types.html#wp16432
which says to use:

...::fromArray([Lcom/google:gwt/core/client/JavaScriptObject;)
(properties)

(note the left square bracket before the L)

> Also, why are the ellipsis used?

to allow for uses such as fromArray("a", "b", "c") instead of fromArray
(new String[] { "a", "b", "c" })

> Do they have a special purpose in GWT?

No (and as with generics, it's hardly more than syntactic sugar, as
the "new String[]" is implied in the example above)

Bobby

unread,
Jul 13, 2009, 11:45:25 PM7/13/09
to Google Web Toolkit
Status update: the library is ready, i'm translating the various JS
samples into GWT to include in the first download, using the same
format as the Google Maps sample app which is contained the in the gwt-
maps-1.0.4.zip available here:
http://code.google.com/p/gwt-google-apis/wiki/Downloads?tm=2

This is the fun part. :)

Bobby
> http://code.google.com/webtoolkit/doc/1.6/DevGuideCodingBasics.html#D...
> links tohttp://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/types.html#wp16432

Eric Ayers

unread,
Jul 14, 2009, 9:54:55 AM7/14/09
to Google-We...@googlegroups.com
Thanks for the update.

Bobby

unread,
Jul 15, 2009, 1:30:30 AM7/15/09
to Google Web Toolkit
I'm adding the GData samples here as i go, if you want to see the
library in action.
http://1.latest.gwt-gdata.appspot.com/v/HelloGData.html

Bobby

Bobby

unread,
Aug 13, 2009, 9:11:35 PM8/13/09
to Google Web Toolkit
In the GData JS library, in IE, AuthSub fails if google.load("gdata",
"1.10"); is asynchronous, after the page has finished processing. For
example, if i place the google.load("gdata", "1.10"); call within the
GWT onModuleLoad method, then AuthSub stops halfway.

To avoid this we can directly add the following at the top of the GWT
html page:
<script type="text/javascript" src="http://www.google.com/jsapi"></
script>
<script type="text/javascript">google.load("gdata", "1.10");</
script>

Or just use the auto-load feature of the JS API to collapse these two
into a single script load.

But this wouldn't make use of the AjaxLoader module and it means that
the GWT app will have to wait for the GData libraries to load before
rendering, etc, instead of doing something like the following:

public void onModuleLoad() {
//render main app here
GData.loadGDataApi(null, new Runnable() {
public void run() {
initialize();
}
});
}

I don't know the reason for this behavior but it could happen if the
gdata library uses document.write for example.

Bobby

On Jul 15, 1:30 am, Bobby <bobbysoa...@gmail.com> wrote:
> I'm adding the GData samples here as i go, if you want to see the
> library in action.http://1.latest.gwt-gdata.appspot.com/v/HelloGData.html

Eric Ayers

unread,
Aug 13, 2009, 9:16:05 PM8/13/09
to Google-We...@googlegroups.com
The gdata init shouldn't use document.write() - you should be able to
call it at any time.

There is a tradeoff of using the AjaxLoader module - it does add more
delay than using the script version. Fortunately, you can code your
app using AjaxLoader and then if you need the speedup, just add the
logic in your host page. AjaxLoader will detect that the jsapi is
already there and bypass it. You can add that check in your version
of GData.loadGDataApi() if you like.
--
Google Code Jam 2009
http://code.google.com/codejam

Bobby

unread,
Aug 13, 2009, 9:29:24 PM8/13/09
to Google Web Toolkit
Another possible cause could be for example if, in the compiled GWT
app, the google.load call happens inside an IFrame.

Currently, with google.load being called from onModuleLoad,
google.accounts.user.login() causes the redirect to the Google
Accounts authorization page, but when it redirects back, with the
token in the URL (for example /HelloGData.html#tokenhere), the token
doesn't get consumed (in IE), and the authentication doesn't succeed.

If GWT is placing the onModuleLoad code inside an IFrame, then it may
cause the GData library to look for the token on the IFrame
window.location, instead of the top's window.location.

Bobby

Bobby

unread,
Aug 13, 2009, 9:46:16 PM8/13/09
to Google Web Toolkit
The onModuleLoad is within an iframe, that's probably the cause. I
think i can find a way around this. For example, i can add the
following method to the GData module:
GData.transferTokenOrSomething();

This function would check the top frame for a token and append it to
the IFrame's location. I'll play around with this.

Bobby

Bobby

unread,
Aug 13, 2009, 10:20:47 PM8/13/09
to Google Web Toolkit
By the way, i've finished porting the samples (70 of them) i'm
currently polishing and commenting the samples code.

I've added specialized Callbacks into the API, for example
BlogEntryCallback (extending AsyncCallback<BlogEntry>) - this meant
adding specialized methods for insert/update/delete, but makes for a
better API. There have been other changes and design choices as well.

In the Maps samples, the create/update features are not working
because of a KML-related defect which i might try to get around with
GWT:
http://code.google.com/p/gmaps-api-issues/issues/detail?id=1585

Other than that i have a small list of items to wrap up (including
this IE issue) and some documentation to write, but nothing major and
i'm counting on having a download by the end of this week or next week
at the latest.

Bobby

Bobby

unread,
Aug 13, 2009, 11:55:19 PM8/13/09
to Google Web Toolkit
This IE AuthSub issue is not because of the IFrame, the transferToken
approach didn't make a difference.

I tried placing the google.load('gdata', '1.10'); call in a button
click event. Here's the code:
<html>
<body>
<img src="logo-small.png" />
<script type="text/javascript" src="http://www.google.com/jsapi"></
script>
<script type="text/javascript">
function loadGData() {
google.load('gdata', '1.10');
}
</script>
<input type="button" value="Load GData" onclick="loadGData();" />
</body>
</html>

If you try this, when you click "Load GData", the page is cleared and
nothing really happens. If you look at the page source after clicking
the button you see the following:
<script src="http://www.google.com/uds/?file=gdata&v=1.10" type="text/
javascript"></script>

This is what would happen if document.write was being used and would
explain a few things.

Eric, does your AjaxLoader module use google.load() from the jsapi?

Bobby

Eric Ayers

unread,
Aug 14, 2009, 12:17:46 AM8/14/09
to Google-We...@googlegroups.com
If you are calling JavaScript inside of a GWT JSNI function, you
should be using $wnd.google.load(...)

Bobby

unread,
Aug 14, 2009, 1:37:30 AM8/14/09
to Google Web Toolkit
This was outside GWT. I'm trying to find the cause of the IE AuthSub
issue outside of GWT first. Basically, when google.load() is called
after the page has finished loading - such as from a button click,
AuthSub doesn't succeed.

Bobby

Bobby

unread,
Aug 14, 2009, 2:53:03 AM8/14/09
to Google Web Toolkit
There are some quirks which are making it difficult to narrow down the
reason why AuthSub fails in IE. So far i know it only happens when
google.load is used with a callback, even when google.load is called
while the page is being loaded.

So something like the following:
<body>
<script>
google.load("gdata", "1.10", myCallback);
</script>
<input type="button" value="login" onclick="google.accounts.user.login
('scope-here')" />
</body>

Will always see the following behavior:
1. User clicks to login.
2. User is redirect to authorization page and clicks to authorize.
3. User is redirected back to the original page, with a token appended
in the URL.
4. Page doesn't consume the token in the URL (the correct behavior is
for the page to place the token in a cookie and remove the token from
the url).
5. User clicks to login again.
6. User gets redirected to authorization page again, and steps 3-6 are
repeated an arbitrary number of times.
7. If, after reaching the authorization page a second time, the user
clicks the browser's back button, causing the browser to go back to
the page that contains the token in the url, the token is successfully
consumed and the user is successfully logged in. Go figure.

Why "backing" into the page causes GData to successfully consume the
token i have no idea - especially since refreshing the page at step 4
has no effect.

My guess is that when backing into the page IE will use a cached
version of the GData script, which is processed immediately and may
make the difference.

Bobby

Bobby

unread,
Aug 14, 2009, 4:53:11 AM8/14/09
to Google Web Toolkit
I may not be able to correct this IE bug, and it may not be desirable
either since it isn't a good idea to have the GWT version introduce
hacks onto the JS library in order to fix a bug - stuff like this is
better off being corrected in the JS version directly. I'll add this
as a defect and deal with it later, the workaround being to use a
script reference to load the API.

I'm starting to think about how to detach the GWT library from the JS
api in the future. Here's what i'm seeing, in the JS API all GData
operations (POST, PUT, DELETE) are sent as POST commands. A POST
variable called HTTP-Method-Override can be used to specify the actual
operation. Cross-domain POSTS aren't a problem, we can just create and
submit a hidden form using some JavaScript.

Since GData supports retrieving data in JSON format, we can use a
JSONP approach to do cross domain reads - this is what the current JS
API does.

This means that in order to detach the GWT version from the JS
libraries we have to:
1. identify the Atom schema for each data type, there are a few
hundred classes.
2. provide a base implementation that can perform cross-domain POSTS
and JSONP reads.

I think #1 can be automated and #2 is sensitive but small.

The end result will be a more GWT-optimizable API which can then grow
at its own pace. The samples and unit tests wouldn't change
significantly, if at all. We can still use overlay types to wrap
around the JSON objects returned from GData. I've taken a closer look
at the GData Java library and i don't think that the GWT and Java APIs
will ever match because the GWT version will need to be callback-based
whereas Java doesn't have this limitation.

Anyway, just some thoughts.

Bobby
> ...
>
> read more »

Bobby

unread,
Aug 24, 2009, 3:36:13 AM8/24/09
to Google Web Toolkit
Version 1.10.1 is available here:
http://code.google.com/p/gwt-gdata/downloads/list

Bobby
> ...
>
> read more »

Bobby

unread,
Oct 21, 2009, 4:55:32 AM10/21/09
to Google Web Toolkit
Version 2.0.1 will be available probably later this month. The IE bug
is gone, which is nice since it makes it possible to use the
AjaxLoader module, which eliminates the need for a script tag and
simplifies loading packages individually.

The samples for 2.0.1 dynamically load packages as needed:
http://gwt-gdata.appspot.com/v2.0.1/HelloGData.html

By the way, even though i've used static initializers for constants,
i'm not seeing any initialization cost. I think maybe GWT is inlining
the initializers, since the initializers are native methods on overlay
types.

Bobby
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages