[GWT] 外部 JS 呼叫 Java static method

看板java作者 (痞子軍團團長)時間11年前 (2014/04/24 13:48), 編輯推噓0(001)
留言1則, 1人參與, 最新討論串1/1
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 -- 錢鍾書: 說出來的話 http://www.psmonkey.org 比不上不說出來的話 Java 版 cookcomic 版 只影射著說不出來的話 and more...... -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.37.105.127 ※ 文章網址: http://www.ptt.cc/bbs/java/M.1398318539.A.066.html

04/24 14:07, , 1F
不客氣XDD 是覺得應該和 JNI 的 Signatures 一樣才這樣猜
04/24 14:07, 1F
文章代碼(AID): #1JMANB1c (java)
文章代碼(AID): #1JMANB1c (java)