[GWT] 外部 JS 呼叫 Java static method

楼主: PsMonkey (痞子军团团长)   2014-04-24 13:48:56
Blog 版:http://blog.dontcareabout.us/2014/04/js-java-static-method.html
BBS 版以 markdown 语法撰写
______________________________________________________________________
内容有点无脑,先把结论写在前面:
> 外部 JS(官方文件称为“handwritten JS”,
> 其实不同 GWT Module 就满足这个条件)要呼叫 Java 的 static method,
> 必须先透过 JSNI 设定 `$wnd.methodName =
> @fooPackage.FooClass::javaMethodName(*)`,
> 后续使用 `$wnd.methodName()` 来达到目的。
>
> 关键在于 JSNI 中:
>
> * `javaMethodName()` 后头不需再加 `()`。
> * `javaMethodName()` 的参数某些情况下可以省略 field descriptor,
> 直接用 `*` 代替。
update:感谢 darkk6(ptt.cc)提醒,让我发现我不但死脑筋,
而且还少测了一种写法... 所以文章就要重新翻修了 (艸
前天被问到一个问题:
“同一个 host page 上两个不同 GWT Module 要怎么沟通?”
我原本以为这不会是问题,
结果回到家实际测了一下才发现根本不是这么一回事 [死]。
一言以蔽之,可以用这个 [stackoverflow][so1] 来解释。
上头发问的内容大抵上就是我原本的想法:用 event bus 来解,
结果是不可行的,不过那不是这篇文章的重点 XD
[so1]: http://stackoverflow.com/questions/17273572/
how-to-communicate-two-modules-in-gwt?answertab=votes#tab-top
为了保险起见实际测试了一下解答的 code,然后就发现根本行不通:
private native static exportMyJavaMethod() /*-{
$wnd.myJavaMethod = @my.package.module1.MyClass1::myJavaMethod;
}-*/;
那个 `myJavaMethod` 没给参数的 field descriptor,
GPE 就报 syntax error、development mode 也一样炸。
回头去确认[官方文件],没想到[官方文件]的程式码一样微妙......
package mypackage;
public MyUtilityClass{
public static int computeLoanInterest(
int amt, float interestRate, int term) { ... }
public static native void exportStaticMethod() /*-{
$wnd.computeLoanInterest = $entry(
@mypackage.MyUtilityClass::computeLoanInterest(IFI)
);
}-*/;
}
我不太确定那个 `IFI` 是啥意思 or 啥缩写...... =="
[官方文件]: http://www.gwtproject.org/doc/latest/
DevGuideCodingBasicsJSNI.html#calling
好,不管这些,自己重新写一个程式测试这个部份:
package foo.client;
//import 略
public class FooEP implements EntryPoint {
@Override
public void onModuleLoad() {
exportJsMethod();
callFooMethod("...");
}
static void javaMethod(String arg1) {
Window.alert("javaMethod : " + arg1);
}
native static void exportJsMethod() /*-{
$wnd.fooMethod = @foo.client.FooEP::javaMethod
(Ljava/lang/String;)();
}-*/;
native static void callFooMethod(String message) /*-{
$wnd.fooMethod(message);
}-*/;
}
结果在 development mode 执行就炸错误,主要错误讯息是
com.google.gwt.core.client.JavaScriptException:
(TypeError) @foo.client.FooEP::callFooMethod()([]):
undefined is not a function
其实在这错误讯息之前就有两个地方散发出怪味道:
1. `$wnd.fooMethod = @foo.client.FooEP::javaMethod
(Ljava/lang/String;)();`,
为什么没有实际给 `javaMethod()` 参数?
等等,这个时间点给他什么都不对啊?
2. 忽略 1,为什么会先跳出 alert 视窗显示 `javaMethod : null`,
然后才炸错误?
如果也在 `callFooMethod()` 里头先卡一行 `$wnd.alert("WTF?")`,
会发现显示 `WTF?` 的 alert 视窗还是会出现,
表示 `callFooMethod()` 有正确被执行到,炸的是 `$wnd.fooMethod()`。
整个看起来,事情好像就有头绪了。
其实 `exportJsMethod()` 的 `$wnd.fooMethod`
根本没有正确 assign 成 `FooEP.javaMethod()`,
而是 assign 成 `FooEP.javaMethod()` 的回传值──根本没这玩意,
所以到 `callFooMethod()` 的时候当然就炸了。
原先我一直死脑筋用 Java 的角度去看,
后来换成 JS 的角度去看其实这样结果很正常。
在 JS 当中一个变量可以代表一个数值、
也可以代表一个 function / method,
如果程式中要执行该 function / method,那就是加上 `()`,
例如在 Chrome console 输入 `alert`
会得到 `function alert() { [native code] }`,
而 `alert("WTF")` 才会真正跳出 alert 视窗。
在上头的 case 当中,我只是要把 $wnd.fooMethod 指定为一段程式码,
根本没有要执行它的意思,所以加上 `()` 根本就是多余且错误阿...
![](http://img.anyanother.com/data/55495.jpg)
所以拿掉后头的空括号,一切就正常了(之前怎么没想过阿阿阿阿 [核爆]),
[官方文件]的那个 `IFI`,
darkk6 猜测是 `int`、`float`、`int` 的缩写,
如今(修正完之后)回头看也很合理了 [死]。
最后不小心看到另一个 [stackoverflow][so2],
发现还有一招里技可以用,
就是直接给 `*` 号,省去打一堆 field descriptor:
native static void exportJsMethod() /*-{
$wnd.fooMethod = @foo.client.FooEP::javaMethod(*);
}-*/;
这有个前提,就是 `FooEP` 中只能有一个 `javaMethod()`,
否则就会炸错误:也就是说,
如果你有两个以上同名的 method,那还是得乖乖写 field descriptor。
另外,在 JSNI 中呼叫 `$wnd.fooMethod()` 时已经是纯粹 JS 了,
所以即使你多传参数、或是少传参数也不会怎么样......
至少 GPE 跟 browser 都没有特别反应。
native static void callFooMethod(String message) /*-{
$wnd.fooMethod();
$wnd.fooMethod(message, "又多余了");
}-*/;
[so2]: http://stackoverflow.com/questions/16080099/calling-gwt-java-function-from-javascript?rq=1
好了,事实证明 GWT 文件也没写得那么好,
除了上次那个很隐晦不想让人知道的 [AutoBean] 之外,
又遇到了一个谜样里技。还是说其实官方文件有,只是我没找到呢...... [泪目]
[AutoBean]: http://blog.dontcareabout.us/2013/12/gwt-autobean.html
====
再次感谢 darkk6 Orz
作者: darkk6 (Mr. Pan)   2014-04-24 14:07:00
不客气XDD 是觉得应该和 JNI 的 Signatures 一样才这样猜

Links booklink

Contact Us: admin [ a t ] ucptt.com