Need help with JSNI

101 views
Skip to first unread message

rjcarr

unread,
Mar 19, 2014, 2:51:30 PM3/19/14
to google-we...@googlegroups.com
I'm trying to export GWT methods using JSNI and I'm not having a lot of luck. And sometimes things happen as they should and other times they don't and it seems to be magic that is making it happen. It seems the export is happening correctly (i.e., javascript can call the GWT methods) but once it gets back to the GWT then things are inconsistent, or at least weird. Here's the basics of what I'm doing:

public class Main implements EntryPoint {
  private Logger logger = null;

  public void onModuleLoad() {
    logger = Logger.getLogger();
    export(this);
  }

  public void log(String level, String msg) {
    logger.debug(msg);
  }

  public native void export(Main main) /*-{
    $wnd.jsni = {};
    $wnd.jsni.log = $entry(main.@org.package.Main::log(Ljava/lang/String;Ljava/lang/String;));
    }-*/;
}


And in javascript I would call this with:

window.jsni.log("warn", "Hello, world!");


And strangely sometimes this works, but other times (during a different compile) I get:

com.google.gwt.core.client.JavaScriptException: (TypeError) stack: TypeError: Cannot read property 'd' of undefined


Which I've tracked down to being the logger object in the log() call being undefined (or null). That is, it always makes it into the "java" code, so the export is working, but there seems to be a problem with accessing local members.

Am I doing something wrong?  Note that I only need to do this for a couple methods so I'd prefer to just do it myself instead of use something like gwtexporter.

Jens

unread,
Mar 19, 2014, 4:42:58 PM3/19/14
to google-we...@googlegroups.com
Is GWT's java.util.logging disabled for the compile that causes troubles? 

-- J.

rjcarr

unread,
Mar 19, 2014, 4:52:13 PM3/19/14
to google-we...@googlegroups.com
No, nothing changes from what I can tell.  I don't mean for you to be distracted when I say it sometimes works.  And the example I gave using a Logger is just one example; I see the same 'undefined' problems no matter what type of member I try to dereference.  I'm more interested in if what I'm doing it correct.

To give more details on the "weirdness", I can sometimes do something like this (modifying my log() method from before):

public void log(String level, String msg) {
    // a utility that writes directly to the console and doesn't use a logging mechanism
    Console.log("logger value: " + logger);
    try {
      logger.debug(msg);
    } catch(Exception e) {}
  }
}

And the console output will be "undefined" but the log message will happen.  But if I take it out of the try then it goes back to saying undefined.  That's what I meant by it is doing "magical" things.


Thomas Broyer

unread,
Mar 19, 2014, 6:30:33 PM3/19/14
to google-we...@googlegroups.com
Beware of JavaScript's 'this'!

$entry(function(a,b) {
main.@my.app.Main::method(II)(a,b);
});

rjcarr

unread,
Mar 19, 2014, 6:50:05 PM3/19/14
to google-we...@googlegroups.com
I've responded a couple times so I apologize if you get multiple copies but it wasn't showing up in the thread.

Just wanted to say this worked and thank you so much.  I've been battling this problem for quite a while.  I don't know why this information isn't in the docs but it should be added right away.

Thanks again!

Jens

unread,
Mar 19, 2014, 7:06:35 PM3/19/14
to google-we...@googlegroups.com
I don't know why this information isn't in the docs but it should be added right away.

Indeed. I also always forget about that 'this' thing and I am pretty sure I would have written the same code as you did in the first post and would have lost some time again until remembering that 

public void log(String level, String msg) {
  logger.debug(msg);
}

will try to access logger on $wnd.jsni when calling it from pure JS (following your example).

I think we should add a non-static method export example to http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html#calling and explain why such an export looks different.

-- J.

Robert J. Carr

unread,
Mar 19, 2014, 7:23:05 PM3/19/14
to google-we...@googlegroups.com
Right, I first followed the static export example and got things working.  Then realized I actually wanted to use it non-statically and got help on this forum with how to include the instance into the export (main.@...).

As I said, it would work sporadically, but not always.  An non-static example would be very useful as I still don't completely understand why it needed to be wrapped with an anonymous function.



--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/vDteixKON4g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

Jens

unread,
Mar 19, 2014, 7:46:49 PM3/19/14
to google-we...@googlegroups.com
As I said, it would work sporadically, but not always.  An non-static example would be very useful as I still don't completely understand why it needed to be wrapped with an anonymous function.

Because $wnd.log = $entry(myInstance.@package.Class::log()) kind of means "assign/copy the method definition of myInstance.log() to $wnd.log". When you now call $wnd.log() from JS, the code inside $wnd.log() is executed in the context of $wnd and not in the context of myInstance. Thats why this inside $wnd.log() is now $wnd and not myInstance

When you wrap it in an anonymous function it means "assign an anonymous function to $wnd.log and when that function executes call myInstance.log()". Now you are calling the real myInstance.log() method and this is what it should be.

-- J.
Reply all
Reply to author
Forward
0 new messages