Search code examples
javajavascriptgwtjsni

GWT JSNI method exposure


I have a question regarding using JSNI to expose one of my GWT methods.

I have am trying to expose a method in one of my GWT classes that fires a message to other UI components.

In my application entry point I expose it with

   public native void exportMethods() /*-{
        $wnd.fireFoo=$entry([email protected]_a::fireFoo(Ljava/lang/String;));
   }-*/;

class_a updates one of its fields, and then calls a static method from class_b.

   public class class_a{

       private String last_msg;

       public void fireFoo(String msg){
           this.last_msg = msg;
           class_b.foo(msg);
       }
   }

class_b calls many other classes and static methods to process the msg

   public class class_b{
       public static void foo(String msg){
       ...//creates a message object and sends it to UI components
       class_c.foo2(msg);
       ...
       }

   }

Basically, all I need to do is pass off a string and call a GWT method. The method (when called from GWT and not handwritten JS) works perfectly. I have also verified that the exposed method will fire a simple alert. I believe the problem lies in calling the other classes' methods.

I get: "(TypeError) Unable to get property 'hv' of undefined or null reference description."

Is there a way to pass off a string to the original GWT method without having to go an expose the countless other methods that it will eventually run through?


Solution

  • Just like in JavaScript, [email protected]_a::fireFoo(Ljava/lang/String;) is a reference to a method, but it doesn't bind that method to the this object at that time. The this from inside the method will be determined at the time the function is called, not the time the reference is retrieved.

    You thus need a delegate:

    var that = this;
    $wnd.fireFoo = $entry(function(s) {
      [email protected]_a::fireFoo(Ljava/lang/String;)(s);
    });
    

    If it indeed works in DevMode as you say, then it's a bug in DevMode.