顯示具有 GWT 標籤的文章。 顯示所有文章
顯示具有 GWT 標籤的文章。 顯示所有文章

2020年6月3日 星期三

GWT 2.9.0 發布

亮點

  • 可以用 jsinterop-base 1.0.0、elemental2 1.0.0、jsinterop-annotations 2.0.0(除了 @JsAsync@JsEnum)做 compile,這會讓 GWT2 將可以用 J2CL 以及這些工具來 compile。
  • 增加 Java language level 9, 10, 11 的支援度。
  • 正式停止在 Java 7 上執行 GWT compiler 與 server side tooling 的支援。在這個版本當中,GWT 還是可以在 Java 7 上 compile,但是不會保證能否運作。未來的版本會以 Java 8+ compile bytecode。這個版本用來測試與提供不同平台上搭配 Java 8, 11, 14 一起運作的方式。

棄用

  • Elemental 已經正式棄用了,這個版本裡頭還有,但是未來的版本當中可能就不會出現。我們建議用 Elemental2 來取代,它可以同時用 GWT2 以及 J2CL compile。
  • 移除 NoSuchMethodException 的模擬。

修正

  • 修正 float[]double[]Arrays.binarySearch()
  • error / exception 增加支援多行訊息。
  • DiskCache 增加關閉的 hook 來清除暫存檔們。
  • 將 Gecko 版號快取起來,以減少在 FireFox 的 CPU 使用率
  • 不再假設「this 一定不是 null」
  • Updates globals for Firefox version 60.0.2, Chrome 66.0.3359.45。
  • 修正 String.regionMatches()
  • 原生的 JsMethods 允許跟實做程式碼以相同名稱共存。
  • 必要時,確保 lambda 的 box、unbox、insert 有消除 cast。
  • Double.compare()Float.compare() 正確地處理負 0。

雜項

  • CLDR 更新到 v.34。
  • Arrays 現在有 implement Cloneable
  • Link backing errors together with a cause attribute, start tracking suppressed errors in addition to the cause in underlying error object.
  • AtomicReference 加到 gwt/emul
  • Propagate script nonces via ScriptInjector
  • 增加 ExecutorServiceScheduledExecutorService 的部份功能模擬。
  • 模擬 java.util.concurrent.Flow
  • 模擬 javax.annotation{,.processing}.Generated
  • goog.global 沒有定義時,讓他變成 $wnd。
  • 增加 when-linker-added element definition。
  • 增加 Reader 以及 StringReader 模擬。
  • 移除 GWT 版本檢查。
  • synthetic method 不會顯示「unusable-by-js」警示。
  • Update unmodifiableList to throw on Java8 methods.
  • 預設關掉 DataflowOptimizer,用到時會發出警告。

更多細節參見 commit log

2015年1月24日 星期六

2014 年 GWT 調查報告中文摘要

原始報告請到 https://vaadin.com/documents/10187/4238532/GWT_report_2015.pdf 下載。 這個連結是在某個 G+ 上頭看到的, 目前 https:/vaadin.com/gwt 的連結還是指向 2013 的版本, 但是 https://vaadin.com/gwt/report-2015 的東西似乎 ready 了?

這是在 2014 年作的調查,所以雖然 vaadin 是標注 2015 年, 我還是以 2014 為篇名。

基本上都只翻譯數據跟(個人認定的)重點,非逐句翻譯。


1. 評價

4.47 分(滿分 5 分)。

這是 1101 份投票的平均分數。有 82% 的人投了 4 分以上。

2014年5月16日 星期五

HandlerManager 與兩個 event package

我大概是當完兵之後才開始用 HandlerManager 作 event bus,目的當然是降低耦合度。起手 reference 是 tkcn 的這篇《利用 HandlerManager 實作共用的 Event Bus》,然後一直以來就爽爽用,沒出啥問題、也沒想過會出問題。今天在 review 別人的 code 才知道有 SimpleEventBus,然後想知道這兩個到底有什麼差別、該用哪一個比較好?沒想到才剛打開 HandlerManager 的 source code,一開頭的 javadoc 就開始噴血:

application developers are strongly discouraged from using a HandlerManager instance as a global event dispatch mechanism.

WTF?不但不建議,而且是強烈不建議?GWT MVP 的文件都還是教用 HandlerManager 阿?

2014年5月11日 星期日

GWT MVP part1

原文網址:http://www.gwtproject.org/articles/mvp-architecture.html

建立大型 application 都有其障礙,GWT application 也不例外。多個開發人員同時在一份程式碼上作業、維護既有功能,可能短時間內就會讓程式碼一團混亂。為了解決這個問題,我們導入 design pattern 來將 project 劃分出不同的責任區。

有很多 design pattern 可以選擇,例如 Presentation-Abstraction-Control、Model-View-Controller、Model-View-Presenter…… 等等。雖然每個 pattern 有其優點,不過我們發現 Model-View-Presenter(以下簡稱 MVP)架構在開發 GWT application 的效果最好。有兩個主要的原因:首先,就像其他 design pattern,MVP 會降低開發行為的耦合度,這讓多個開發人員可以同時工作。再者,MVP 會盡可能降低 GWTTestCase 的使用度。GWTTestCase 會需要 browser,但是大多數程式碼只要輕量、快速、不需要 browser 的 JRE 測試。

這個 pattern 的核心是把功能分散到各個元件,這在邏輯上是有意義的。但在 GWT 中還有一個明確的重點,是讓 View 的部份盡可能簡單,以減輕對 GWTTestCase 的依賴、降低整體的測試時間。

一旦你瞭解這個 design pattern 的原理,那麼建立以 MVP 為基礎的 application 就會直覺又簡單。我們將用一個簡單的通訊錄系統為例子,協助你聊解這些概念。這個系統可以讓使用者增加、編輯、檢視存放在 server 上的聯絡人清單。

2014年4月24日 星期四

外部 JS 呼叫 Java static method

內容有點無腦,先把結論寫在前面:

外部 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)提醒,讓我發現我不但死腦筋,而且還少測了一種寫法… 所以文章就要重新翻修了 (艸

2014年4月1日 星期二

GWT RPC 的 deserialize 行為與 IE8

原文網址:http://blog.oio.de/2014/03/28/gwt-rpc-deserialization-vs-ie8/


幾乎每個 web 開發人員都知道,當 JS 執行時間過久 browser 就會跳出討厭的對話框問你要不要取消。在 IE 上頭會顯示「這個網頁的指令碼造成 Internet Explorer 執行速度緩慢」。

這篇文章將說明 IE8 的特殊行為、它如何影響 GWT RPC 的 deserialize 機制、以及如何解決這些問題。

2013年12月29日 星期日

GWT 的 AutoBean

AutoBean 是目前打算拿來在 GWT 中處理 JSON 的工具。 不過在講正事之前,先扯兩段雜談 [毆飛]

雜談 1:這樣也可以?

要不是要弄 web API,其實也不會想碰 JSON, GWT RPC 好好的幹麼弄什麼 JSON [遠目]。 不過 server side 要處理 JSON 其實有 GSON, 正常 encode / decode 真的都還蠻簡單的, 簡單到不知道能介紹什麼 XD。 是說 LaPass(ptt.cc)因為有一個我覺得有點詭異的需求, 結果挖出了 TypeAdapterFactory 的用法, 看起來真的很乾淨很炫(炫到都快看不懂了 [遮臉]), 只能說好 library 如當是也。

理所當然的,會想看看有沒有 GWT 版的 GSON, 結果看到 bGwtGson 這玩意差點噴出來。 因為他的作法是用 GWT RPC 把東西丟到 server side, 這樣 server side 就有 GSON 可以用了… 揪咪…

我都不知道該說牛逼還是坑爹,這世界果然很廣大阿 [握拳]

喔對,順帶一提,GSON 在 AppEngine 上也可以使用。

雜談 2:謎樣裏技?

我搞不太懂 AutoBean 在 GWT 當中扮演什麼樣的角色? 彷彿還蠻多人在用的(因為大家都炸同樣的問題… Orz), 但是官方指南似乎沒有這個東西(JavaDoc 當然還是有), 教學文件只有出現在 google code 的 wiki 上, 所以這是裏技嗎?

我比較怕這是即將被拋棄的裏技 Orz

畢竟要在 GWT 裡頭處理 JSON 並不是太麻煩。 官方指南建議的 JSNI / Overlay Types 寫起來堪稱簡單直覺, 尤其是跟 AutoBean 相比的話 [死]。 再不然 GWT-Jackson 好像也是種選擇?

剛好兩者的風格我都不愛 [淚目]

最大的哏在於 AutoBean 並沒有辦法直接處理 List<T> 這種東西, 這個 bug 在 2011.10 被提出之後, 2012.11 最後一個 comment 之後就無聲無息了, 目前最新的 GWT 2.5.1 還是有同樣的問題 Zzzz,只能靠 workaround。 後頭會詳述這些事情 [死]。

怎麼用?

好了,終於要進入正題了。 [握拳]

GWT 已經內建 AutoBean,所以不用另外掛 jar 檔, 但是要在 gwt.xml 當中補上:

<inherits name="com.google.web.bindery.autobean.AutoBean"/>

如果你要把下面這個 JSON 字串轉成 Foo 的 instance

{
    "uid":"cde6c847-d072-4d33-82bd-93fa4710dc9b",
    "limit":50,
    "deleted":true,
    "update":1388157386000
}

首先… Foo 得是個 bean 的 interface,定義一堆 getter/setter, 名稱得跟 JSON 裡頭的一致:

interface Foo {
    public void setUid(String uid);
    public void setLimit(int limit);
    public void setDeleted(boolean deleted);
    public void setUpdate(Date update);
    public String getUid();
    public int getLimit();
    public boolean isDeleted();
    public Date getUpdate();
}

轉換的時候需要先建立一個 factory,通常會這樣寫

interface MyFactory extends AutoBeanFactory {
    AutoBean<Foo> foo();
}
MyFactory factory = GWT.create(MyFactory.class);

然後… 終於可以 decode 了:

String foo = "{" +
        "\"uid\":\"cde6c847-d072-4d33-82bd-93fa4710dc9b\"," +
        "\"limit\":50," +
        "\"deleted\":true," +
        "\"update\":1388157380000" +
    "}";
Foo instance = AutoBeanCodex.decode(factory, Foo.class, foo).as();

encode 的話就是:

String fooJson = AutoBeanCodex.encode(
    AutoBeanUtils.getAutoBean(instance)
).getPayload();

如果願意在 MyFactory 裡頭加一個 method:

interface MyFactory extends AutoBeanFactory {
    AutoBean<Foo> foo();
    //下面這個是新增的
    AutoBean<Foo> genFooBean(Foo foo);
}

那不用 AutoBeanUtils.getAutoBean() 而是

String fooJson = AutoBeanCodex.encode(
    factory.genFooBean(instance)
).getPayload();

有沒有比較快樂就見仁見智,不過後面會需要用到後面這招, 或著這麼說比較實在: 「請忘記 AutoBeanUtils 吧」。

注意事項

如果到這邊你還能忍受 AutoBean, 那先講幾個我已經炸到,但可以理解的哏, 主要是跟 GSON 的差異。

  1. Gson.toJson() 遇到 false / null 值不會省略該 field, 但是 AutoBean 會。 也就是說,如果 foo.setDeleted(false);, 那麼 AutoBeanCodex.encode() 出來的字串不會看到 deleted

    當然,這其實不妨礙正常運作。 GSON 的作法可能有些人還會覺得怪?

  2. 日期(java.util.Date)的處理。 Gson.toJson() 會用 Date.toString() 作值(反之亦然), 但是 AutoBean 則是用 Date.getTime()(反之亦然)。 只能說還是統統用 long 表示日期就算了 (然後在 JSON 當中最好還把這數字當成字串, 免得像 32bit 的 PHP 還給你耍花招 [怨念ing])。 至於 Joda 要解決的議題… 遇到再說 XD

有遇到會再補上來 Orz

List 的炸點

如果你永遠不會 decode / encode 一個 array 或是 List, 那恭喜你,除了寫法稍稍扭曲一點之外, AutoBean 是可以接受、也算好用的(應該啦…)。

實際上… 別鬧了,怎麼可能不處理 List

於是 AutoBean 就成了茶几──上頭擺滿了悲劇。

decode

GSON 吐出來的東西來看,一個 List<Foo> 的 instance 會長這樣 (喔對,我把 update 的型態改成 long 了 XD):

[
    {"uid":"cde6c847-d072-4d33-82bd-93fa4710dc9b",
     "limit":50,"deleted":false,"update":"1388157380000"},
    {"uid":"a391dedf-1f81-4380-a712-59eac4d9aea3",
     "limit":50,"deleted":false,"update":"1388157380000"}
]

想依樣畫葫蘆比照辦理時… 等等,AutoBeanCodex.decode() 的第二個參數要給什麼? 然後於是有人弄出了這個 workaround

首先,要建一個 interface 來代表 List<Foo> 這玩意:

interface FooList {
    public void setList(List<Foo> list);
    public List<Foo> getList();
}

factory 的 interface 則是:

interface MyFactory extends AutoBeanFactory {
    //下面這個暫時用不到
    AutoBean<Foo> genFooBean(Foo foo);

    AutoBean<FooList> fooList();
}

最後,要對拿到的 JSON 字串動手腳,變成這樣:

    FooList fooList = AutoBeanCodex.decode(
        factory, FooList.class, "{\"list\":" + foo + "}"
    ).as();
    List<Foo> instance = fooList.getList();

簡單地說,就是 Java 的部份你要讓他有個 class 為依歸, 但是光這樣還不夠,因為 AutoBean 不知道要從何處理起, 所以 JSON 的部份你也要偽造一下……

等等,還沒完,好戲壓箱底、好酒沈甕底, encode 的部份那才叫經典。

encode

要把一個 List<Foo> 轉成 JSON,這到底是有多難? 不難,如果把剛剛 AutoBeanCode.decode() 出來的 fooList 再次轉成 JSON, 那麼只要 factory 加上

interface MyFactory extends AutoBeanFactory {
    //下面這個暫時用不到
    AutoBean<Foo> genFooBean(Foo foo);

    AutoBean<FooList> fooList();
    //下面這個是新增的
    AutoBean<FooList> genFooListBean(FooList instance);
}

立馬就轉,沒有問題!(也完全沒意義 ==”)

AutoBeanCodex.encode(
    factory.genFooListBean(fooList)
).getPayload();

如果是把既有的 List<Foo> instance 轉換, 依照上面的邏輯,得先實做那個毫無意義的 FooList

FooList fooList = new FooList() {
    List<Foo> list = new ArrayList<Foo>();

    @Override
    public void setList(List<Foo> list) {
        this.list = list;
    }

    @Override
    public List<Foo> getList() {
        return list;
    }
};

//FooImpl 就容許我跳過,反正就是 implements Foo 的東東
fooList.getList().add(new FooImpl());

AutoBeanCodex.encode(
    factory.genFooListBean(fooList)
).getPayload();

執行上面這段程式碼,你就會發現 AutoBeanCodex.encode() 快樂的炸了 NPE,而且完全搞不懂發生了什麼事情。

這是個已知的 bug(Issue 6904), 雖然不知道會不會有人去解…… Orz。 而世界還真的是很廣大,有人也找出了 workaround, 解法就是你不能直接丟 FooImpl 的 instance, 得用 MyFactory.genFooBean() 產生出 AutoBean<Foo>, 再藉由它(as())取得 Foo 的 instance 才可以…… 寫的我自己都亂了,看 code 比較實在:

interface MyFactory extends AutoBeanFactory {
    AutoBean<Foo> genFooBean(Foo foo);
    AutoBean<FooList> fooList();
    AutoBean<FooList> genFooListBean(FooList instance);
}

fooList.getList().add(
    //原本是 new FooImpl()
    factory.genFooBean(new FooImpl()).as()
);

AutoBeanCodex.encode(
    factory.genFooListBean(fooList)
).getPayload();

套最近流行的句型: 「如果這不叫脫褲子放屁,我還真他媽的不知道什麼才叫脫褲子放屁」

喔對,無論 genFooBean() 還是 genFooListBean() 都不能用官方文件用的 AutoBeanUtils.getAutoBean()。 如果拿他替換 genFooBean(),一樣噴 NPE; 如果拿它替話 genFooListBean(),不會噴 NPE, 而是轉換出來的 JSON 字串會是 null。

WTF

結尾 murmur

GSONAutoBean 相比是很有趣的。 一個是完美到不需要瞭解內部到底發生什麼事情, 一個則是太糟糕了,所以根本不想瞭解。

短時間之內,我可能還是不會放棄 AutoBean, 除非 GWT 2.6 就遺棄 AutoBean, 或是找到更好的 tool(而不是 GWT-Jackson 那種 style)。 都花了這麼多時間了,就看看能被炸到走到什麼程度。

寫到後來,都不知道到底是在介紹推廣還是在吐槽。 只能說,嗯… 我對 GWT 真的很有愛…… [遠目]

2013年12月15日 星期日

2013 年 GWT 調查報告中文摘要

原始報告請到 http://vaadin.com/gwt/report-2013 下載(要輸入 EMail 帳號)。 除了序言之外,其餘都只翻譯數據跟(個人認定的)重點,非逐句翻譯。


序言

在 2012 年第一次作 GWT 狀況調查 時,收到的回覆數量淹沒了我們。 我們把調查報告取名為《The Furture of GWT》(譯名:GWT 調查報告), 因為我們想知道「GWT 衰老中」這個謠言到底有多少可信度。 在超過 1300 個回應裡,我們、以及全世界都看到了 GWT 活蹦亂跳的樣子。 許多大型企業用 GWT 來建構大型的 application, 對 GWT 投注的資源也在增加。

在《GWT 調查報告 2013 版》中, 我們想要知道 GWT 未來該如何發展?(第六節) 開發團隊在用什麼 Java 跟 GWT 的版本?以瞭解 哪些地方需要支援?(第四節) 你們需要哪些 extension、在找哪些 framework?(第五節) 為了取得背景以及人口統計學的資料, 我們也問了關於你的團隊(第一節)、 你在寫的 application(第二節)、 以及你如何開發 application(第三節)。 有了這些資訊整合成這份報告, 我們覺得這是最綜合性的調查,可以引領 GWT 很長一段路。

在 2013 年,有 12 月的研討會(gwtcreate.com), 有令人興奮的 GWT 3.0 的計畫、 還有許多大公司投入 GWt 作為他們未來的技術; 我們知道 GWT 跨出了不只一大步。 2013 年 GWT 委員會也決定了未來的 release 步調: 每年一個大改版以及一個小改版。

這份調查是由 Vaadin、 Ray Cromwell(Google 代表、現任委員會主席)、 Daniel Kurka(mGWT 與 GWT-phonegap 的 Google 開發者)、 Artur Signell(Vaadin 代表)、 Bhaskar Janakiraman(Google)、 Colin Alworth(Sencha)、 Christian Goudreau(Arcbees)、 Konstantin Solomatov(Jetbrains)、 Mike Brock(RedHat)、 Stephen Haberman(Bizo)、 Joonas Lehtinen(Vaadin)以及 Thomas Broyer。 你可以在這份報告中看到他們的意見與反應。

這份調查報告在 GWT.create 2013 發表, 友超過 600 個熱心的 GWT 開發者出席這個年度最大的 GWT 活動。 我們同樣感謝超過 1400 位受訪者所花的時間與坦白, 期待看到你們的意見!

1. 關於開發團隊

團隊大小

GWT 開發團隊的平均人數是 12.5 人,而中位數則是 8 人。這跟去年的調查相同。 我們也問了過去 12 個月團隊大小的變化。

  • 47%:一樣
  • 41%:擴編
  • 10%:縮編
  • 3%:我只是小員工,不確定…

(兩張團隊大小的統計分佈圖)

團員組成

以八人團隊為例,任務分配為:

  • 2.7 人:後端開發者
  • 2.0 人:前端開發者
  • 1.3 人:測試人員
  • 0.9 人:PM(project / product)
  • 0.6 人:設計師
  • 0.6 人:死星上的人?

地理分佈

  • 58%:歐洲(上升 8%)
  • 25%:北美洲
  • 8%:亞洲(譯註:可惡,我應該去參加調查的 [毆飛])
  • 4%:南美洲
  • 2%:澳洲
  • 2%:非洲

2. GWT 用在哪裡

畫面數量

  • 48%:超過 20
  • 22%:11~20
  • 21%:5~10
  • 10%:1~4

20 是一個魔術數字。調查大型 app 的畫面數量應該很有趣。

Christian:少於 5~7 個畫面的 app 實在太小了,為什麼會用 GWT 呢? 這是個有趣的問題。

compile 時間

  • 1~3 分鐘:27%(去年 31%)
  • 3~10 分鐘:46%(去年 48%)
  • 10~30 分鐘:20%
  • 超過半小時:7%

對照去年的數據,可以代表 project 的規模越來越大。

Ray 與 Bhaskar:要改善 compile 時間有點難、需要一點時間來克服。 不過我們已經開始嘗試 incremental / modular compilation system。

寫給誰用

  • 35%:內部使用
  • 17%:公開且免費
  • 43%:公開但收費
  • 5%:其他

用來寫什麼

  • 46%:商業內部 application
  • 33%:商業外部 application
  • 13%:content-rich 網站
  • 2%:Portlet
  • 1%:遊戲
  • 5%:其他

Ray:看到有人用 GWT 寫遊戲實在很棒。 GWT 可以讓你在 Web 與 Android 之間共用程式碼, 藉由 PlayN 這種 library 也可以拓展到 iOS 上。

browser 支援度

(註:下列數據分別為 希望 2013 年有支援 / 希望 2014 年有支援

  • IE 6 跟 7:14% / 9%
  • IE 8:54% / 44%
  • IE 9:79% / 66%
  • IE 10:80% / 76%
  • IE 11:NaN / 70%
  • Safari:18% / 62%
  • Chrome:94% / 93%
  • Firefox:94% / 92%
  • iOS:NaN / 49%
  • Android:NaN / 50%

Joonas:IE6/7 終於快死光了,所以 GWT 3.0 可以不用鳥它們了。 不過看起來 2014 年還是要很痛苦地去支援 IE8/9, 因為需求量看起來還是蠻大的。

Ray:對於改進 GWT 核心而言,IE6/7/8 是可悲的毒藥, 有很多 API 沒辦法增強就是因為老一輩的 browser 沒辦法處理。 網頁正轉型為 mobile 跟 HTML5, 要整合過時的 browser 會讓這個轉型過程變得很困難。

Thomas:看到 IE6/7/8 加起來還不少,讓我很沮喪。

裝置支援度

(註:下列數據分別為 2012 年 / 2013 年

  • Desktop:98% / 99%
  • Tablet:36% / 45%
  • Phone:26% / 30%
  • 其他:2% / 2%

3. 如何用 GWT 建置 App?

怎麼作 UI?

  • 48%:用 Java 刻
  • 46%:UiBinder
  • 6%:GWT designer

Christian:我不懂為什麼這年頭還會有人想要 Java 刻 UI? 每個語言都有對應的 UI 描述方式。 ActionScript 有 MXML、 JavaScript 有 HTML、 .NET 有 XAML。

Daniel:看到這麼多人用 Java 刻 UI? 明明 UiBinder 就是比較好的方式。我們需要大力推廣 UiBinder。

Mobile App 開發環境

  • 27%:mGWT
  • 16%:gwt-phonegap
  • 16%:JS library
  • 15%:PhoneGap
  • 10%:Vaadin Touchkit
  • 17%:其他

後端通訊方式

  • 53%:GWT-RPC
  • 11%:Request builder
  • 7%:Request factory:
  • 7%:自製
  • 6%:Vaadin
  • 4%:RESTY
  • 3%:gwt-dispatch
  • 3%:gwt-platform

Ray:GWT-RPC 在小型 app、快速開發方面實在超有力的, 但是在 compile 時間以及 interoperability 上會花很多時間。 JAXRS 是 GWT 3.0 考慮的方法之一,可能會提供更好的中間層。

Daniel:在決定 GWT 3.0 以後的 RPC 系統時, 我們應該要記得「很多人喜歡 GWT RPC 的簡單好用」這件事。

IDE

  • 76%:Eclispe
  • 18%:IDEA:
  • 5%:Netbeans
  • 1%:其他

Christian:我個人最愛 IDEA 的 GWT plugin,是目前最成熟的。

Ray:我是 IDEA 的愛好者,它把寫 JSNI/JavaScript 程式碼這檔事做的很好。

如何作測試?

  • 49%:手動
  • 18%:Selenium
  • 13%:JUnit(GWTTest)
  • 13%:沒有測試 UI 這種事啦…

DevMode 還是 Super DevMode?

  • 74%:DevMode
  • 14%:兩個都用
  • 5%:Super DevMode
  • 5%:孟獲孟獲孟獲…

Thomas:看到 Super DevMode 成長真好。 未來要讓所有 browser 支援 DevMode 不太可能。 Super DevMode 的比例成長應該有部份會歸應於 mobile 平台。

Joonas:我們真的應該讓 Super DevMode 變成預設值。 用它來執行程式會比較接近實際的運算效能。 我覺得 DevMode 的優勢在於設定比較方便。

4. 用什麼版本?

GWT 版本

  • 79%:2.5
  • 11%:2.4
  • 3%:2.3
  • 3%:trunk 版
  • 2%:孟獲孟獲孟獲…
  • 1%:2.1
  • 1%:2.0

Thomas:看到有 3% 的人用 thunk 版真的超驚訝的。 我們計畫推出 nightly build,明年這個比率可能會增加。

JDK 版本

  • 37%:Java 6
  • 56%:Java 7
  • 8%:Java 8

Ray:我可以發布一個解法,只讓 client 的碼用 Java8。 但是 Java6 無所不在,希望多一點人可以願意去試試看。 Java8 的 lambdas 超好的, 讓 async callback 還有 collection 操作變得很愉快。

Joonas:Vaadin 7 已經支援 Java 8 了, 我希望我們可以在 GWT 3 當中用到 Lambdas 的優點。

會在 client 端的程式碼用 Java 8 的功能嗎?

  • 52%:不會讓 project 設定變複雜的前提下才會考慮
  • 27%:希望 client 跟 server 端用不同版本的 Java
  • 12%:沒興趣
  • 6%:其他
  • 2%:孟獲孟獲孟獲

Daniel:80% 的人會想要在 GWT 中用 Java8,這相當好。 我們必須找出一個好方法讓 server side 必須用 Java6 的人也能運作。

5. 外掛、framework…

GWT 用起來的產能如何?

  • 不想再用:2%
  • 不是很好:7%
  • 中規中矩:32%
  • 相當優秀:44%
  • 無可匹敵:15%

下一個 project 會用 GWT 嗎?

  • 84%:會
  • 16%:不會

不用 GWT 會用什麼 framework?

  • 5%:Play
  • 5%:JSF
  • 5%:Errai
  • 6%:SmartGWT
  • 8%:Dart
  • 11%:SpringMVC
  • 12%:Vaadin
  • 14%:JavaScript
  • 14%:Angular

Ray:GWT 3.0 會有一個新的 JS interop system, 銜接向 Polymar 或是 Angular 就不用寫 JSNI 的程式碼而變得更容易。 如此一來,想要用什麼 framework 就去用吧。

用哪方面的外掛?

回收的問卷中有 87% 的人使用了外掛,其中:

  • 23%:UI 功能(例如 GWT-dnd、GWT-fx)
  • 20%:application 架構(例如 GWT-presenter)
  • 15%:資料存取(例如 GWT-rpc、GWT-dispatch)
  • 12%:server 存取(例如 Google API、GWT-bootstrap)
  • 9%:application 功能(例如 GWT-platform)
  • 4%:data handling(例如 gilead)
  • 5%:其他
  • 13%:沒有用外掛

外掛去哪找?

  • 55%:就 google 嘛
  • 19%:自幹一個
  • 13%:GitHub
  • 11%:gwtproject.org
  • 2%:其他

你會整合既有 JS 到 project 中嗎?

  • 62%:會
  • 32%:不會
  • 3%:其他
  • 2%:孟獲孟獲孟獲…

6. GWT 的未來

GWT 的 bug

  • 73%:從來沒有回報過 bug
  • 13%:有
  • 14%:有,但是沒有修正

Thomas:GWT 真的夠好嗎?我不確定…… 到底是大家沒有被 bug 炸到,還是他們懶得回報 bug?

GWT 的光明面

每人兩票:

  • 60%:產能(cross-browser、不用弄一堆 JS)
  • 32%:執行速度(不是 compile 速度)
  • 24%:可模組化(可以團隊方式寫 GWT,不會互相影響) (掌控大型、很多功能的程式)
  • 19%:發現 bug 並解決的速度很快
  • 18%:ecosystem 中的開發工具
  • 17%:可靠度
  • 13%:可用度
  • 13%:產能(開始用 GWT 很容易)
  • 9%:DevMode 的重新整理速度
  • 7%:程式碼大小
  • 6%:有很多 widget 可以用
  • 5%:widget 品質很好
  • 5%:設計 application 風格 / application 外觀
  • 3%:有很多外掛
  • 2%:外掛品質很好
  • 2%:compile 時間
  • 3%:其他

GWT 的黑暗面

每人兩票:

  • 55%:compile 時間
  • 29%:DevMode 的重新整理速度
  • 19%:設計 application 風格 / application 外觀
  • 13%:有很多 widget 可以用
  • 13%:程式碼大小 (譯註:圖表的文字是 3%,但是長度是 13% 的大小。用後者。)
  • 11%:發現 bug 並解決的速度很快
  • 10%:產能(開始用 GWT 很容易)
  • 9%:widget 品質很好
  • 7%:ecosystem 中的開發工具
  • 6%:執行速度(不是 compile 速度)
  • 5%:可模組化(可以團隊方式寫 GWT,不會互相影響) (掌控大型、很多功能的程式)
  • 3%:可用度
  • 3%:有很多外掛
  • 2%:外掛品質很好
  • 2%:產能(cross-browser、不用弄一堆 JS)
  • 1%:可靠度
  • 6%:其他

Daniel:GWT 2.6 就已經有一些關於 compile 時間的改善。

Thomas:GWT 3.0 的重點會在改善 compile 時間以及 DevMode 的 refresh 時間上。

對委員會有什麼感覺?

  • 17%:GWT 感覺比以前有活力
  • 22%:對 GWT 的未來比以前有信心
  • 17%:roadmap 更清楚了
  • 28%:沒啥變化耶其實
  • 10%:現在對 GWT 比較沒信心
  • 6%:其他

2013年7月5日 星期五

GWT 與 WebSocket [上]

前言

這一陣子因為專案需要 server 與 browser 之間有即時雙向溝通的能力,所以就用了 websocket。 又由於 server 端綁定 PHP(還好 browser 也綁定 Chrome XD), 再加上傳輸的資料沒有很複雜,單純字串就可以解決, 所以沒有用現有的 GWT websocket library,統統自己來了...... [遮臉]

於是也就順便寫了這篇文章,借 websocket 介紹下面兩個主題:

  1. GWT 如何整合 JavaScript 程式碼(JSNI)
  2. EventHandler 的使用

(當然行有餘力的話也想涵蓋 GWT RPC,不過目前無法)

這三個主題在作〈GWT 版 GAE Channel API〉的時候都有用到 (但是 RPC 的部份只抄其 code、不明其理 [遮臉]), 不過拿 websocket 來介紹可能比較實在一點,GAE 的 channel API 可能太少人用了 [死]。

2013年4月11日 星期四

GWT 的優點與缺點

原文網址:http://www.gmarwaha.com/blog/2011/05/09/gwt-pros-and-cons/

註:原文寫於 2011.05.09


我愛 JavaScript。jQueryMooTools 出來之後, 讓我對 JavaScript 的愛又增加了好多倍。 如果要我對所有我開發的 web application 做出選擇, 我會從上面兩個 framework 當中選一個。 但是在這一行,我不得不一次又一次地屈服於客戶的壓力、 用他們選擇的技術來作業,無論他們的選擇對或錯 (付錢就是老大啊...... Orz)。 有一個客戶讓我接觸到 GWT 的世界。

幾年前當 GWT 剛發佈的時候,我曾經試了一下。 我不怎麼喜歡,所以我甩了 GWT 就再也沒回頭看過它一眼。 但是在過去六個月用 GWT 作業之後,我對這個 framework 有稍微不同的印象。 我仍然不會說 GWT 是什麼拯救世界的神兵利器, 但至少它沒有我想像的那麼糟糕。 我把對這個 project 的觀察結果紀錄下來,好的壞的都有, 對之後要導入 GWT 的開發人員來說可能有點用處。

2012年12月9日 星期日

2012 年 GWT 調查報告中文摘要

原始報告請到 https://vaadin.com/gwt/report-2012 下載。雖然 Vaadin 有收集 EMail 之嫌 [炸],但不可否認這份報告實在做的非常有愛,值得給他 EMail 帳號以資鼓勵。另,本篇摘要翻的很隨性,只保證數據沒有打錯,其他就...... [毆飛]


GWT 在 2012 年有許多令人興奮的內容、也改變了未來發展 GWT 的方式。 在產品與社群前所未有地茁壯的同時,大家想問:「阿下一步咧?」

Google 在六月的時候把 GWT 變得更開放。 為了未來的發展,成立了 GWT 指導委員會, 裡頭有 Vaadin、Google、Sencha、RedHat 等等。 我們開始設法收集大家拿 GWT 作啥、想許什麼願望。

這個 GWT 研究是由 Vaadin 以及一堆人努力而成, 在這份報告裡頭也會看到他們的意見。

在回收的一千三百多份問卷當中,都回答了超過三十個以上的問題, 我們相信這會是最完整的調查報告。

2012年6月17日 星期日

GWT 的 Super Dev Mode 是怎麼運作的?

原文網址:http://tbroyer.posterous.com/how-does-gwts-super-dev-mode-work

GWT 的 Super Dev Mode(別名:Super Draft Mode)一個月前第一次 tease,然後持續發展到上個禮拜正式 land,for your testing pleasure.(譯註:翻譯不能 Orz)

這個 Dev Mode 強化了哪些東西?

在回答這個問題前,讓我們先回頭了解一下 Dev Mode 的構造,它是由 browser plugin 與 code server 所組成、用 TCP 的 socket 彼此溝通以在 JVM 中執行你的 GWT 碼然後跟 browser 互動(以及執行 JSNI),而不用先跑一次漫長的 compile 過程。GWT 的 Dev Mode 也可以(額外)嵌入一個 servlet container(預設是 Jetty 6,也可以用其他的),所以它可以執行 server 端的程式碼。在 GWT 開發指南中可以找到這張圖:
Dev Mode 其中一個優點是在 JVM 中執行你的 client 端程式碼,你可以使用標準的 Java debugger,有 breakpoint、可以觀察變數......等等。此外,server 端的程式碼也在同一個 JVM 上頭執行,就更容易 debug(不過只適用於小程式)。缺點就是需要一個 browser plugin(它得在 UI thread 中阻斷 JS 的執行,但是同步的 XMLHttpRequest 沒辦法提供夠好的效能、Dev Mode 又很聒噪地一直發,更不用說同步的 XHR 將要被淘汰了。)

2012年6月9日 星期六

GWT 已死!

原文網址:http://www.guynirpaz.com/2012/04/28/gwt-is-dead/
翻譯:Alice Liu
校正:PsMonkey

GWT 已經死了啦... 至少對 Totango 來說是這樣的。我們正處於將所有 Totango UI 轉換到 native HTML5 的最後階段。我知道這對於有在關注前端 JavaScript framework 的人而言可能不是什麼新聞,但是在過去幾個月中,我被問了好多次關於使用 GWT 的看法,現在我要清楚表明——我不推薦任何人開始使用 GWT,因為這是個沒有未來的 project。

2012年5月1日 星期二

GWT Elemental library

原文來自於 +Ray Cromwell 以及後續某些 comment。

特別感謝 +YC Ling 指正 bleeding edge 用法。

Ray Cromwell:
為甚麼 GWT 的 SuperDevMode 還沒有 commite 到 trunk?幾個星期前,我提到一個 Google 內部、給 GWT 用的 library,簡稱「clevername」。由於種種原因,目前 SuperDevMode 跟 Google 內部的東西產生了一些相依性,其中一個就是「clevername」。

2012年4月16日 星期一

自製 GWT 版 GAE Channel API

雖然之前寫〈用 Channel API 實作簡易聊天室〉,已經算是把 Channel API 順過一遍了,但問題是......
有了 GWT,誰還想去碰 JS 啊...... 囧>
於是 google 了一下,發現這兩個 project:gwt-gae-channelgwt-channel-api 有將 Channel API 包好給 GWT 用,不過各有優缺點,茲簡單分析如下:

2012年3月30日 星期五

區分 GWT 程式碼的執行環境

這是在勁過呂布的噗浪上遇到的問題。

起因是傳給 String.split() 的 RegExp,Java 與 JavaScript 的寫法相似、但不是完全相同(參見 GWT 文件),也就會遇到「development mode 下正確、但 compile 之後得不到預期結果」的窘況。再者,如果 client/server 端都用 Java 寫,也會擴大這個問題的麻煩度。

這時候我們需要 GWT

(謎之聲:你不就在寫 GWT 了 [指])

這裡是指 com.google.gwt.core.client.GWT。這個 class 提供 isClient()isScript()isProdMode() 理論上與 isScript() 等意)這兩個 static method。

isScript() 是辨別程式碼是以 JavaScript 的方式執行、還是以 Java 的方式執行。在 development mode 下會回傳 false,在 compile 時才由 GWT compiler 改成回傳 true。

isClient()(邏輯上)不會區分是不是 development mode,純粹辨別程式碼是在瀏覽器上頭執行,還是在 JVM 上頭執行。

理解這種文字遊戲有點麻煩,還是來寫個程式比較實在。首先是 client 端的程式:
public class Foo extends Composite
 public static final RpcServiceAsync rpc = GWT.create(RpcService.class);
 private VerticalPanel panel = new VerticalPanel();
 public Foo(){
  String result = "[client] GWT.isClient() = " + GWT.isClient()
    + ", GWT.isScript() = " + GWT.isScript();
  panel.add(new Label(result));

  rpc.gwtMethod(new AsyncCallback<String>() {
   @Override
   public void onSuccess(String result) {
    panel.add(new Label("[server] "+result));
   }
   
   @Override
   public void onFailure(Throwable caught) {}
  });
  
  this.initWidget(panel);
 }
}

而 Server 端 RpcServiceImpl 的 method 長這樣:
 public String gwtMethod() {
  return "GWT.isClient() = "+GWT.isClient()
   + ", GWT.isScript() = "+GWT.isScript();
 }

在 development mode 下,會得到:
[client] GWT.isClient() = true, GWT.isScript() = false
[server] GWT.isClient() = false, GWT.isScript() = false
實際 deploy 到 web server 上,會得到:
[client] GWT.isClient() = true, GWT.isScript() = true
[server] GWT.isClient() = false, GWT.isScript() = false
如此一來,雖然遇到了抽象滲漏的現象,但我們還是可以藉由  GWT.isClient()GWT.isScript() 判斷是 development mode 還是 production mode、是 client 端還是 server 端、給予對應 RegExp,來解決這個問題。

2012年2月29日 星期三

GWT 繁體中文徵稿計畫

徵稿主題:
  • core GWT
  • GPE
  • 3rd party library(不含 GXT、SmartGWT 此類 library)

2012年2月14日 星期二

GWT、GAE 的日期問題

開發環境:GWT 2.4.0、GAE 1.6.1、GPE 2.5.1、Objectify 3.0

正在作一個預約系統,很自然會有「取出某天所有預約」之類的需求,所以將 class 設計成這樣,期望能節省一些麻煩:
class Booking{
    Date date;
    int hour;  //時間間隔以「小時」為單位
    //skip other field
}

由於 GAE 的 Datastore 理論上沒有提供在 query 時可以卡入日期函數,所以如果不對日期作處理,下面這段「取得今天的預約」會完全取不到任何東西:
Objectify ofy = ObjectifyService.begin();
ofy.query(Booking.class).filter("date", new Date()).list();  //empty list

2012年1月8日 星期日

改善 array 的記憶體使用方式

原文網址:https://plus.google.com/u/0/110412141990454266397/posts/U7wMJv2cNnj

本週 GWT 改良進度:加強 array 的記憶體使用方式。

GWT 會給予每個 type 一個稱為 queryId 的數字,透過檢查這個數字來模擬出 Java 的 runtime type check。舉例來說,這段程式碼「foo instanceof IFoo」會去取得 IFoo 的 queryID,假設是 42。

接著,在設定 object 的 prototype 時,會加上 map,例如:
Foo.prototype.castableTypeMap = { 42: 1 };
如此一來,像「foo instanceof IFoo」會轉換成「!!foo.castableTypeMap[42]」,在這個例子會回傳 true。

一切都運作完好...... 除了 array。GWT 中模擬 array 的方式,並不是透過修改 Array.prototype,而是在 native 的 JS Array object 當中加入 field,所以「x=new Foo[10]」最終會變成像這樣:
x=makeArray({42:1});
發現問題了嗎?每一次 allocation 會使用一個新的 array literal,即使它們共用相同(且 immutable)的 literal。這會浪費 JS VM 的記憶體。

2012年1月6日 星期五

更改 gwt.xml 需 refresh 兩次才見效

測試環境:GWT 2.4.0、Eclipse 3.7、GPE 2.5、GWT Developer Plugin 1.0.9738(Chrome)

今天輾轉發現 gwt.xml 導致的奇妙問題:
在 Development Mode 下,修改 gwt.xml 的內容,browser 第一次 refresh 依然保持原設定,第二次 refresh 才會呈現修改後的結果。
已知會造成這個現象的是 <stylesheet> 以及 theme 的 <inherits>。<entry-point> 不會有這個問題,其餘未測。

由此延伸出這些測試:
  • 如果單純修改 <stylesheet> 的 CSS 檔案、在第一次 refresh 就會呈現修改結果。
  • 以 Chrome Developer Tools 觀察:<stylesheet> 的 CSS 檔案以及 theme 對應的 CSS 檔案,都是由 foo.nocache.js 所呼叫
  • 修改 client 下的 .java 檔,在第一次 refresh 就會呈現修改結果......
最大的爆點還是在於為甚麼是「第二次」呢?需要重開 Development Mode 之類的行為才會正確,還比較合邏輯些?GWT 的 code server 到底做了什麼啊啊啊啊....... <囧>

ps. 雖然有點多餘,不過 Mac 跟 Windows XP 的測試結果一樣......