Experience with JsInterop status

517 views
Skip to first unread message

Marcin Okraszewski

unread,
Apr 28, 2015, 10:15:52 AM4/28/15
to google-web-tool...@googlegroups.com
Hi,
I was playing a bit with the new JsInterop on trunk build. After some conversation with Goktug, I was to write some of issues I've found. It was April 3 build, sorry didn't check if anything changed since then. So, here it goes:
  1. @JsFunction exported to JS doesn't have apply() and call() operations. Apply() is used by JQuery (2.1.3) to call callbacks, so basically it wasn't possible to add handlers using JQuery. See other thread on this: https://groups.google.com/forum/#!topic/google-web-toolkit/PHtfLTSAJDM 
  2. js() function is not yet available.
  3. I wasn't able to call methods on jQuery object returned from JSNI when using just @JsType annotation. It only worked when I used @JsType(prototype="jQuery")
  4. @JsProperty set on methods were not available in JS. 
  5. Couldn't access class with @JsExport annotation from JS.
I've workarounded the @JsFunction issue by adding .apply() in JS, so I've made it work. And I must tell, the new JsInterop is really GREAT!

I also used @JsType with @JsProperty to access a JSON returned from server. I just used JSON.safeEval() and casted to @JsType interface. It worked great! I hope it could be a replacement for me of AutoBeans, if only the JS arrays and Java collections were unified. 

Regards,
Marcin Okraszewski

Jens

unread,
Apr 28, 2015, 12:38:39 PM4/28/15
to google-web-tool...@googlegroups.com

  1. @JsFunction exported to JS doesn't have apply() and call() operations. Apply() is used by JQuery (2.1.3) to call callbacks, so basically it wasn't possible to add handlers using JQuery. See other thread on this: https://groups.google.com/forum/#!topic/google-web-toolkit/PHtfLTSAJDM 
Pretty interesting how to model that JQuery callback with JsInterop. Basically when you do $("p").click(handler) then JQuery sets "this" for the handler to the element the event occurred on so you can do 

$("p").click(function() {
   $(this).slideUp(); // slides the clicked p element up
});

I think you can't really do that with just JsInterop. I think your Java callback must be JQueryCallback.exec(Element elem, Event e) and you have to use JSNI to create a pure JS function that passes "this" as "elem" to the JQueryCallback.

-- J.


 

Goktug Gokdogan

unread,
Apr 28, 2015, 2:32:02 PM4/28/15
to google-web-toolkit-contributors
Thanks for the feedback.

On Tue, Apr 28, 2015 at 6:40 AM, Marcin Okraszewski <okr...@gmail.com> wrote:
Hi,
I was playing a bit with the new JsInterop on trunk build. After some conversation with Goktug, I was to write some of issues I've found. It was April 3 build, sorry didn't check if anything changed since then. So, here it goes:
  1. @JsFunction exported to JS doesn't have apply() and call() operations. Apply() is used by JQuery (2.1.3) to call callbacks, so basically it wasn't possible to add handlers using JQuery. See other thread on this: https://groups.google.com/forum/#!topic/google-web-toolkit/PHtfLTSAJDM 
We are going to fix this before the release; it's in the queue.
 
  1. js() function is not yet available.
There are some disagreements in the team, so this may not make to v1.0.
 
  1. I wasn't able to call methods on jQuery object returned from JSNI when using just @JsType annotation. It only worked when I used @JsType(prototype="jQuery")

Can you elaborate more? Can you send a small code snippet that reproduces the problem?
 
  1. @JsProperty set on methods were not available in JS. 

JsProperty on methods doesn't work yet if you implement the interface in java (though you can call it if the interface is implemented by javascript). You can use @JsType on concrete classes with public fields instead for now.
 
  1. Couldn't access class with @JsExport annotation from JS.

This needs some code snippet as well so we can reproduce it.

 
I've workarounded the @JsFunction issue by adding .apply() in JS, so I've made it work. And I must tell, the new JsInterop is really GREAT!

I also used @JsType with @JsProperty to access a JSON returned from server. I just used JSON.safeEval() and casted to @JsType interface. It worked great! I hope it could be a replacement for me of AutoBeans, if only the JS arrays and Java collections were unified. 

Regards,
Marcin Okraszewski

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/af52b996-9bec-41d0-9768-934e0371270a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Marcin Okraszewski

unread,
Apr 29, 2015, 3:32:40 AM4/29/15
to google-web-tool...@googlegroups.com
This is definitely problematic. I didn't give it too much though, but I think it would be great if we could opt-in to get the this from JavaScript. Something like this: 

@JsFunction
public interface HandlerWithThis {
   public void onEvent(@JsThis Element target, Event e);
}

If you need the JavaScript this, then you just add it as parameter to method with @JsThis annotation. As currently @JsFunction is not a JavaScript function, but an object that pretend the function, it should be possible to implement apply() and call() in such a way, that it passes this if there is a @JsThis parameter in the method signature. In case you don't need this, you just don't specify such parameter; in such case the method signature would be void onEvent(Event e). This would be much nicer then telling, you need to go to JSNI to do that. 

Do you think it could be done like this?

Thanks,
Marcin


Ray Cromwell

unread,
Apr 29, 2015, 4:02:46 AM4/29/15
to google-web-toolkit-contributors

Lambda's are inner classes, so there is always a 'this' bound to the generated instance, otherwise, the handling method wouldn't be invokable. Imagine if you were implementing this with JSNI:

class HandlerWithThisImpl implements HandlerWithThis {
   public void onEvent(Element target, Event e) { ... }
}

You'd have to write a wrapper that did this:

static native JavaScriptObject makeFunction(HandlerWithThis impl) /*-{
    return function(e) { impl.@onEvent(*)(this, e); }
}-*/;

But to make referential integrity work so that a HandlerWithThis passing into JS and back into Java always converts to the same function and object reference, you'd have to generate a lot more boilerplate.


Instead, to make @JsThis work efficiently, you'd have to do something like this with the magic makeLambdaFunction

/**
* Create a function that applies the specified samMethod on itself, and whose __proto__ points to
* <code>instance</code>.
*/
public static native JavaScriptObject makeLambdaFunction(JavaScriptObject samMethod,
JavaScriptObject instance, int jsThisArgPosition) /*-{
var lambda = function() {
var args = arguments;
if (jsThisArgPosition >= 0) {
args.splice(jsThisArgPosition, 0, this);
}
return samMethod.apply(lambda, args);
}
lambda.__proto__ = instance;
return lambda;
}-*/;
It's feasible, but I think the community needs to chime in.  IIRC, the DOM APIs have changed over the years to include the context as a field of the event argument. 

But perhaps when you look at libraries like Ember, Angular, React, Backbone, et al, all common is it for the 'this' to be bound, passing this explicitly as a parameter?

Typical Google coding style internally is if you want to use this, you use Function.bind() to set it to what you want when you pass in a handler function to something.

Rebinding this from the calling context seems iffy and dangerous when you think about Java code.




--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

Marcin Okraszewski

unread,
Apr 29, 2015, 5:58:34 AM4/29/15
to google-web-tool...@googlegroups.com
Hi Ray,
Fully agree with your last statement. For me, definitely more Java than JavaScript, the whole idea of changing this is slightly weird. I get the Function.bind(), when you pass a function somewhere, but changing this on caller side seems strange to me. 

I don't know how often such mechanism are used in JS libraries. For named jQuery example, actually there is also the Event object passed, which has a target element which is the same as the overridden this. So in fact you can do the same without having access to this from JavaScript. So maybe it is not that much problematic as I thought. 

Marcin
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.

Marcin Okraszewski

unread,
Apr 29, 2015, 10:53:37 AM4/29/15
to google-web-tool...@googlegroups.com
Hi Goktung,
I've compiled the latest version from trunk and rechecked those items you wanted the snippets for. 


  1. I wasn't able to call methods on jQuery object returned from JSNI when using just @JsType annotation. It only worked when I used @JsType(prototype="jQuery")

It didn't happen this time. So either 
 
  1. Couldn't access class with @JsExport annotation from JS.

I had multiple tries of using @JsExport as well as @JsNamespace. This is one of them:

public class Hello {
@JsExport("interop.Hello")
public Hello() {
}
@JsExport
public String sayHello() {
return "Hello World!";
}
}

JavaScript:

      var hello = new interop.Hello();
     alert(hello.sayHello());

Result:

Uncaught ReferenceError: interop is not defined

Marcin
 

Marcin Okraszewski

unread,
Apr 29, 2015, 10:58:31 AM4/29/15
to google-web-tool...@googlegroups.com
Maybe to supplement a bit - the JavaScript code is run in onclick handler, so GWT is already loaded. A wider scope would be:

    <script type="text/javascript" language="javascript">
      function sayHello() {
     var hello = new interop.Hello();
     alert(hello.sayHello());
      }
    </script>

...

    <button onclick="sayHello();">Say hello</button>

Marcin

Goktug Gokdogan

unread,
Apr 29, 2015, 5:20:01 PM4/29/15
to google-web-toolkit-contributors
I think this could be handled by @JsConvert that is specific for jQuery instead of a custom annotation.

Goktug Gokdogan

unread,
Apr 29, 2015, 5:24:15 PM4/29/15
to google-web-toolkit-contributors
On Wed, Apr 29, 2015 at 7:53 AM, Marcin Okraszewski <okr...@gmail.com> wrote:
Hi Goktung,
I've compiled the latest version from trunk and rechecked those items you wanted the snippets for. 

  1. I wasn't able to call methods on jQuery object returned from JSNI when using just @JsType annotation. It only worked when I used @JsType(prototype="jQuery")

It didn't happen this time. So either 
 
  1. Couldn't access class with @JsExport annotation from JS.

I had multiple tries of using @JsExport as well as @JsNamespace. This is one of them:

public class Hello {
@JsExport("interop.Hello")

JsExport is no longer fully qualified, you need to supply JsNamespace. Try following:

@JsNameSpace("interop") @JsExport
        class Hello {
           public Hello() {}
           public String sayHello() { .. }
        }

Also you need to put @JsType if you want to call sayHello from javascript.
        
 
public Hello() {
}
@JsExport
public String sayHello() {
return "Hello World!";
}
}

JavaScript:

      var hello = new interop.Hello();
     alert(hello.sayHello());

Result:

Uncaught ReferenceError: interop is not defined

Marcin
 

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

Marcin Okraszewski

unread,
May 4, 2015, 7:07:21 AM5/4/15
to google-web-tool...@googlegroups.com
Hi,
Sorry for the delay. I still wasn't able to make @JsExport work for me. One thing I was for sure missing is I've never used the class in my GWT project. It was referenced only from JS. Once I instantiated the class from the module load, it started to complain about @JsExport on non-static method, which I interpret that it wasn't processed earlier. I also tried with compiled version served from a webserver, not from Super Dev Mode. In case it was happening in dev mode only. 

The method now looks as below and I'm still having errors that "interop" is undefined. I attach the project in question.

A word of comment on @JsType - that was completely not intuitive that I still need to add @JsType if I use @JsExport.  

@JsNamespace("interop") 
@JsExport
@JsType
public class Hello {
@JsExport
public Hello() {
}
public String sayHello() {
return "Hello World!";
}

@JsExport
public static String sayHelloStatic() {
return "Hello World!";
}
}

Regards,
Marcin Okraszewski


JsExport is no longer fully qualified, you need to supply JsNamespace. Try following:

@JsNameSpace("interop") @JsExport
        class Hello {
           public Hello() {}
           public String sayHello() { .. }
        }

Also you need to put @JsType if you want to call sayHello from javascript.
        
 
public Hello() {
}
@JsExport
public String sayHello() {
return "Hello World!";
}
}

JavaScript:

      var hello = new interop.Hello();
     alert(hello.sayHello());

Result:

Uncaught ReferenceError: interop is not defined

Marcin
 

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.
interop.zip

Jens

unread,
May 4, 2015, 7:38:04 AM5/4/15
to google-web-tool...@googlegroups.com

A word of comment on @JsType - that was completely not intuitive that I still need to add @JsType if I use @JsExport.

Yeah thats why there is a discussion in [1] to make it more intuitive. Feel free to provide some additional input. 


-- J.

Goktug Gokdogan

unread,
May 4, 2015, 5:29:11 PM5/4/15
to google-web-toolkit-contributors
On Mon, May 4, 2015 at 4:07 AM, Marcin Okraszewski <okr...@gmail.com> wrote:
Hi,
Sorry for the delay. I still wasn't able to make @JsExport work for me. One thing I was for sure missing is I've never used the class in my GWT project. It was referenced only from JS.

We already have a test covering that and it is passing (see MyClassExportsMethodWithoutReference)
 
Once I instantiated the class from the module load, it started to complain about @JsExport on non-static method


Are you passing the flag to enable JsInterop for your project?
 
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/da3a45aa-08ef-419a-8cfa-0007a1fc9487%40googlegroups.com.

Marcin Okraszewski

unread,
May 4, 2015, 5:46:50 PM5/4/15
to google-web-tool...@googlegroups.com
Are you passing the flag to enable JsInterop for your project?

 I was adding  "-XjsInteropMode JS" only in SuperDevMode. This question made me realize I didn't for the compilation, when I was testing in external web server. So it works like charm with normal compilation running on external web server, when I add " -XjsInteropMode JS" to compilation parameters. I now feel like in those support quotes - "Did you plug your computer?" ... Sorry I did take you so much time for finding yet another user error. 

Regards,
Marcin

Goktug Gokdogan

unread,
May 4, 2015, 5:54:15 PM5/4/15
to google-web-toolkit-contributors
No worries.

One thing I didn't fully understand is; is this still broken for SuperDevMode or not?

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

Marcin Okraszewski

unread,
May 5, 2015, 3:20:39 AM5/5/15
to google-web-tool...@googlegroups.com
I wasn't able to make it run in SuperDevMode. Worked only in the normal compilation. The idea to try it with normal compilation was from this thread: https://groups.google.com/forum/#!msg/google-web-toolkit-contributors/u1BKRUsjjgI

The launch config is part of the project attached to my yesterday message: https://groups.google.com/d/msg/google-web-toolkit-contributors/QrkNflMKe9E/-3XhHdOXfDsJ
The arguments passed to dev mode are as follows: "-superDevMode -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -startupUrl index.html -logLevel INFO -codeServerPort 9997 -port 8888 -XjsInteropMode JS -war C:\workspaces\gwt-demo\interop-problems\war com.cloudorado.jsinterop.InteropProblems"
I'm testing with build from trunk done morning Apr 29. 

Regards,
Marcin


On Monday, 4 May 2015 23:54:15 UTC+2, Goktug Gokdogan wrote:
No worries.

One thing I didn't fully understand is; is this still broken for SuperDevMode or not?
On Mon, May 4, 2015 at 2:46 PM, Marcin Okraszewski <okr...@gmail.com> wrote:
Are you passing the flag to enable JsInterop for your project?

 I was adding  "-XjsInteropMode JS" only in SuperDevMode. This question made me realize I didn't for the compilation, when I was testing in external web server. So it works like charm with normal compilation running on external web server, when I add " -XjsInteropMode JS" to compilation parameters. I now feel like in those support quotes - "Did you plug your computer?" ... Sorry I did take you so much time for finding yet another user error. 

Regards,
Marcin

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.

Goktug Gokdogan

unread,
May 5, 2015, 1:05:50 PM5/5/15
to google-web-toolkit-contributors
If you clear the cache, does it help? (You can clear it by visiting the SuperDevMode URL where there is a button for it)

On Tue, May 5, 2015 at 12:20 AM, Marcin Okraszewski <okr...@gmail.com> wrote:
I wasn't able to make it run in SuperDevMode. Worked only in the normal compilation. The idea to try it with normal compilation was from this thread: https://groups.google.com/forum/#!msg/google-web-toolkit-contributors/u1BKRUsjjgI

The launch config is part of the project attached to my yesterday message: https://groups.google.com/d/msg/google-web-toolkit-contributors/QrkNflMKe9E/-3XhHdOXfDsJ
The arguments passed to dev mode are as follows: "-superDevMode -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -startupUrl index.html -logLevel INFO -codeServerPort 9997 -port 8888 -XjsInteropMode JS -war C:\workspaces\gwt-demo\interop-problems\war com.cloudorado.jsinterop.InteropProblems"
I'm testing with build from trunk done morning Apr 29. 

Regards,
Marcin


On Monday, 4 May 2015 23:54:15 UTC+2, Goktug Gokdogan wrote:
No worries.

One thing I didn't fully understand is; is this still broken for SuperDevMode or not?
On Mon, May 4, 2015 at 2:46 PM, Marcin Okraszewski <okr...@gmail.com> wrote:
Are you passing the flag to enable JsInterop for your project?

 I was adding  "-XjsInteropMode JS" only in SuperDevMode. This question made me realize I didn't for the compilation, when I was testing in external web server. So it works like charm with normal compilation running on external web server, when I add " -XjsInteropMode JS" to compilation parameters. I now feel like in those support quotes - "Did you plug your computer?" ... Sorry I did take you so much time for finding yet another user error. 

Regards,
Marcin

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/bffa2a4f-8b2e-4f5c-aed6-46f1529167e6%40googlegroups.com.

Marcin Okraszewski

unread,
May 5, 2015, 3:19:30 PM5/5/15
to google-web-tool...@googlegroups.com
It worked! But I had to also restart the SDM. When I just cleaned the cache and reloaded the page it claims no files were changed - see below. Only when I cleaned and then restarted SDM it started to work.

GET /clean/interop_problems
   Cleaning disk caches.
      Cleaned in 2ms.
GET /recompile/interop_problems
   Job com.cloudorado.jsinterop.InteropProblems_1_2
      starting job: com.cloudorado.jsinterop.InteropProblems_1_2
      binding: user.agent=safari
      skipped compile because no input files have changed
      0,043s total -- Compile completed

Marcin

--
You received this message because you are subscribed to a topic in the Google Groups "GWT Contributors" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit-contributors/QrkNflMKe9E/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/CAN%3DyUA0WZFPQ%2B2YzG5xXTPjd6waN8ZQkGJs%3D3SLoKMF09SMXrA%40mail.gmail.com.

Goktug Gokdogan

unread,
May 21, 2015, 9:49:40 PM5/21/15
to google-web-toolkit-contributors
Ok, JsFunction call/apply issue should be fixed as of https://gwt-review.googlesource.com/#/c/12810/. Can you verify that for me?

You cannot still access JQuery bound 'this'. However note that the same issue also exists for ES6 arrow functions.
According to [1] this could be worked around in JQuery's case via event.currentTarget

This required some restrictions and I put others as well so that one day we can generate a completely real function from it.

Marcin Okraszewski

unread,
May 22, 2015, 5:35:45 AM5/22/15
to google-web-tool...@googlegroups.com
Hi,
It works like a charm now! 

For the event.currentTarget, yes this is true, and I also pointed it in this thread earlier https://groups.google.com/forum/#!msg/google-web-toolkit-contributors/QrkNflMKe9E/cyhaHJGwtV8J . Actually good to know ES6 it won't work lambdas too, which should mean overriding "this" should fade out in some future. 

Marcin


On Friday, 22 May 2015 03:49:40 UTC+2, Goktug Gokdogan wrote:
Ok, JsFunction call/apply issue should be fixed as of https://gwt-review.googlesource.com/#/c/12810/. Can you verify that for me?

You cannot still access JQuery bound 'this'. However note that the same issue also exists for ES6 arrow functions.
According to [1] this could be worked around in JQuery's case via event.currentTarget

This required some restrictions and I put others as well so that one day we can generate a completely real function from it.

On Wed, Apr 29, 2015 at 2:19 PM, Goktug Gokdogan <gok...@google.com> wrote:
I think this could be handled by @JsConvert that is specific for jQuery instead of a custom annotation.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages