Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
142 views
in Technique[技术] by (71.8m points)

jsni - Calling GWT Java function from JavaScript

I am a newcomer to GWT and JavaScript. There are similar question of this type I have tried to follow, but I keep failing.

I have a GWT app, I need to call a Java function from Javascript( on the onclick of a href tag, in particular.) Following is what I have done.

public class JSNITest {

 public static void handleAnchorClick(int a , int b) {
   Window.alert("Current row and Column is " + a + "  " + b);
 }

 public static native void exportMyFunction()/*-{
    $wnd.handleAnchorClick = function(param1,param2){
        @company.package.class.JSNITest::handleAnchorClick(*)(param1,param2);
 }-*/;

}

And in the HTML,

<a href="javascript:handleAnchorClick(a1,a2);">link</a> 

(a1 , a2) are two integer variables in my code. I have also called EnclosingClass.exportMyFunction() in the entry point function. I keep running into various kinds of exceptions(No Such class exception). Can someone please correct me?

Regards

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let me explain a bit more about exporting GWT stuff to the JS world. You have several options to do that, but I will focus on three methods.

[EDITED]

0- JsInterop: GWT maintainers are working in a new feature to easily export java methods to javascript, and wrap javascript objects. The feature was very experimental in 2.7.0 lacking some features, but in 2.8.0 will be almost functional. Please take a look to the Design Document, and other discussions in the mailing list.

[END]

1- JSNI: The first one is to write your own jsni, in this case you have to be aware about the possible mistakes you could make. Basically these mistakes are because you have to know how to deal with types. In your case if you want to get a javascript array (like you are asking in your comment below), the solution could be:

public static native void exportMyFunction()/*-{
  $wnd.handleAnchorClick = @company.package.class.JSNITest::handleAnchorClick(*);
}-*/;

public static void handleAnchorClick(JsArrayMixed args) {
  Window.alert("Current row and Column is " +
                args.getNumber(0) + "  " + args.getNumber(1));
}

public void onModuleLoad() {
  exportMyFunction();
}

//javascript code
window.handleAnchorClick([1,2])

Note that JSNI only allows you to pass primitive types (except long) and JavaScriptObject objects. So when passing a javascript array, you have to receive it with a JavaScriptObject like in the example. In this case, since javascript only uses a type for numbers, args.getNumber will return always a double, and you have to convert in java.

2- gwt-exporter For exporting large projects, or when you need to handle complex objects and classes I'd rather use gwt-exporter

static class MyClass implements Exportable {
  @Export("$wnd.handleAnchorClick")
  public static void handleAnchorClick(double[] args) {
    Window.alert("Current row and Column is " +args[0] + "  " + args[1]);
  }
}

public void onModuleLoad() {
  GWT.create(MyClass.class);
}

//javascript code
window.handleAnchorClick([1,2])

gwt-exporter will deal with any kind of primitive types (even with long) myfunc(long[] args), with var-args myfunc(long...args), it supports method overload, and much more.

3- gwtquery Finally if you prefer gwtquery, you can use a technique to add function properties to any js object like window

// The GQuery Properties object is able to wrap a java Function object
// into an js property.
Properties wnd = window.cast();
wnd.setFunction("handleAnchorClick", new Function() {
  public void f() {
    // Get the js arguments[] array
    JsArrayMixed args = arguments(0);
    // Get the first element of the arguments[] array
    JsArrayMixed ary = args.getObject(0);

    Window.alert("Current row and Column is " +
                  ary.getNumber(0) + "  " + ary.getNumber(1));
  }
});

//javascript code
window.handleAnchorClick([1,2])

With gquery you can use the gwt JsArrayMixed class which always returns a number as a double, or you can use a JsCache which allows to convert numbers to any other numeric type in java ((JsCache)ary.get(1, Integer.class)

As a summary, I would rather use gwt-exporter as the first option because it is specialized in handling this problematic. As a second option, I would use gquery which is a serious complement to gwt. Finally, I would avoid to use hand-written jsni when possible, Javascript is normally a source of issues and mistakes (think that the main goal of gwt is not to deal with js).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...