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

2019-06-04

JSON 日期碎碎念

最近(終於)在測 gwt-jackson,負責在 server side 噴 JSON 的是 Gson,然後測到日期(java.util.Date)的時候炸了一輪,所以來碎念一下留個紀念… XD

一開始以為是 gwt-jackson 炸掉,畢竟 GSON 資格老關係好(?),GWT 現在還有多少人在用都是個問題 lol。但是狗了一圈沒發現啥災情,事情開始有點詭異…

那找「gson date」試試看… WTF?GSON 預設的日期格式會隨平台不同而變?這就別提什麼 W3C 之類的標準了,根本亂搞一通嘛… =="

不過至少有解,就是可以用 new GsonBuilder().setDateFormat() 來設定 format 然後用這個 builder 來建立 Gson instance。

那麼,什麼是 JSON 標準定義的日期格式呢?根據這個 stackoverflow 的說法,JSON 根本沒做出定義… =="

好吧,至少 JS / W3C 貌似有,就是 ISO-8601。

因為懶得查,所以直接狗「java dateformat 8601」,我的搜尋結果第一條是 stackoverflow,不過那是要把字串還原回 Date,不太對題。第二條跟第三條(居然)是簡體中文,都是對岸的 CSDN。

先說第三條,文章裡頭給的 pattern 是 yyyy-MM-dd'T'HH:mm:ss.SSS'Z',hmmm… 看起來跟前面 stackoverflow 附的範例一樣,丟下去跑也能正常 parse,太好了可以收工了… 才怪… 得到時間不對,整整多了 8 小時。WTF?時區問題?

算啦算啦… 去測第二條吧,直接拿文章內說可行的 yyyy-MM-dd'T'HH:mm:ss:SSSZZ 來試試看… 連 parse 都過不了?WTF?等等,為什麼反覆測試下發現有時候會 parse 過、而且值也正確?但有時候卻又 parse 不過?幹這是七月半提前報到嗎?

鬼打牆了 n 分鐘之後,終於發現… 測試會過的時候是測完第三條之後把 Z 前後的單引號拔掉,而測試不過的時候是直接複製第二條的文字…

對,X 他 X 的第二個給的 pattern 根本有問題,按照 ISO-8601 的規格,在 sec 跟 ms 中間應該是「.」而不是「:」。肉眼不仔細比對根本很難發現… Orz

到了這個時候,真的是被嚇到了,乖乖回頭看文件。在 Java API 的定義當中,「X」跟「Z」都表示時區,「X」是 ISO-8601 格式、「Z」是 RFC-822 格式(不過目前看不出差異)。ISO-8601 要求日期與時間之間以一個寫死的大寫「T」連結,寫成 Java 的 pattern 就要前後加上單引號。所以第三條 pattern 尾巴的「Z」是寫死不變的。那,為什麼 parse 會過呢?

在 ISO-8601 當中規定,如果時區剛好是 UTC(零時區)就顯示 Z,所以得到的是合法的字串,但是除非人在 UTC 不然解出來的實際 Date 就會有時差問題… Orz

心得與結論:

  • 即使有名有號的 library 還是有可能存在奇妙的行為。即使到現在我還是無法替 Gson 在日期上的作法想出任何合理的理由…
    • 寫這篇文章的時候認真找了一下,原來 Gson 有開過 issue-281 還 close 了,整個看起來有點莫名而且最後路人們還是在用 GsonBuilder 這招? WTF?
  • google 出來的結果未必可信,即使排名在很前面。stackoverflow 上也是。像這個解答還有 62 個推,底下也只有一個人指出這是不對的答案。
  • 雖然說官方文件也不是不會出錯,但相比來路不明的 blog,機率還是低的多(雖然啃起來也難過很多)

2014-02-05

GWT 與 HttpClient 的版本衝突

標題好難下,不過說穿了其實根本也沒什麼。 [死]

故事是這樣的:在一個既有的 GWT project 中想在 server side 用 HttpClient 抓 web API 的東西,抓了 4.2.3 版回來,想說先寫個 application 來測,結果一直炸 java.lang.NoSuchMethodError,明明我只跑最簡單的範例阿阿阿阿混蛋:

public static void main(String[] args) throws Exception {
    System.out.println(
        Request.Get("http://localhost:8080/BSS.html")
        .execute().returnContent()
    );
}

狗了一下好像沒人有我這樣的問題,該不會只是因為我沒用 Maven 吧 [胡思亂想ing]。於是先弄個乾淨的 Java project……. 沒問題;那在 GWT project 下用 JSP / Servlet 執行 HttpClient 碼…… 也沒問題 [死]。

停下來想了一下,該不會 GWT 本來就有用 HttpClient?GWT RPC 底下用 HttpClient 好像完全合情合理,只是 HttpClient 的版本不同結果就哭哭了?結果還果真如此,上面那個例子中找不到的 setConfig() 的 HttpRequestBase,是用 gwt-div.jar 裡頭的版本。

基本上在不想搞懂 classloader 以及 Eclipse 設定之類 blahblah 的討人厭東西,這個 issue 就到這邊為止了,反正不用要 application 就沒事了 [毆飛]

只是我常常遇到官方 example 跑不起來,這到底是怎樣的人品阿阿阿阿 [淚奔]

2013-11-20

viz.js 使用小心得

上一篇提到了我最後選擇了 viz.js,經過一段被炸飛的使用時間之後,來補充一些實戰上的其他心得…… [淚目]

  1. 用 viz.js 來 render DOT 碼時,如果 label 有 \,畫面上不會顯示出來。
  2. DOT 碼中有中文(或著說非 ASCII),在 GWT 當中執行時會一直炸 parse 錯誤。原本以為是 GWT 的問題、因為把同樣的 DOT 碼用純 HTML 來跑就(幾乎)沒遇到問題。後來爬了一下 viz.js 的 issue,發現這個 issue 14,原來這是一個已知的 bug。後頭有一個日本人提供了一個堪稱我看過最詭異的 work around。假如原本的 JS 要這樣寫:

    var dot = DOT_GENERATOR();
    var svg = Viz(dot, "svg");
    

    現在要改成:

    var dot = DOT_GENERATOR();
    var svg = Viz(dot + new Array(dot.lengh).join(" "), "svg");
    

    真的有效,但是也真 WTF 的不明所以 [死]。

  3. 有一個 repo RiveraGroup/viz.js 是從 viz.js fork 出去的。它有直接提供 viz.js 檔、README.MD 還有列出可以 support 哪些 GraphViz 的 layout、以及輸出的 format。不過在不嚴謹的測試之下,發現 RiveraGroup 的版本跟 viz.js 已經有所不同,至少 viz.js 不支援 fdp 這個 layout(例如這個範例),但是 RiveraGroup 的版本有(每次執行的結果還不一樣 ==”)。
  4. 承上,viz.js 的 Viz() 可以接收三種 format,分別是:

    • dot
    • svg
    • ps

    在 browser 的環境下,好像只有 svg 這個 format 比較有意義……

至於其他關於 DOT 語言的炸點…… 就是另外一個故事了 [淚目]

2013-11-08

JS 版 GraphViz 初步 survey 結果

正在寫一個輔助工作的系統。需要把一堆有順序關係的資料轉換成圖表。

一開始先是找到 arborjs.org 的這個 showcase,我還蠻喜歡它的效果,看著 node 飄來飄去想要找一個比較舒服的位置,很有療癒的效果(謎之聲:WTF?)。但是這個 project 實在找不到文件,正在從 cdoe 裡頭試圖 farm 用法的時候, tkcn 大人給了一個關鍵字:「GraphViz」。

幹,原來有這種東西 [死]

GraphViz 弄了一個叫做 dot 的描述語言,來表達 node 跟 node 之間的關係、以及 node 的形式等等。至於圖會長得怎樣就看 rendering engine 怎麼噴(是說我也不是很 care 啦 XD)。既然知道了這個好東西,就開始找看看有沒有 JS 版的 rendering engine。

一開始找到的是 livizjs 這個 repo,也有 demo 頁面。不過一開始在 Chrome 上頭就炸了 exception 不能順利執行,倒是 Firefox 沒有這個問題。然後… 這也是一個沒有說明文件的東西… 而且一堆路徑、DOM id 還 hardcode 寫死。到這裡也都還撐得住。等到寫完資料轉成 dot 格式,然後用正式資料去 run 的時候就悲劇了。SVG 的大小不知道在那一行程式當中被限定住,node 數少的時候沒有問題,node 數一多就爆邊界、還不知道要怎麼調整。接連 combo 攻擊下我放棄了,重新 survey。

最後找到 viz.js 這個 repo,基本上也是顯示成 SVG,不過不像 livizjs 有提供運算過程、動畫之類的花俏功能。雖然依然沒有文件 [淚目],不過用起來很簡單,只要把 dot 碼傳進物件中就好:

<script src="viz/viz.js"></script>
<script>
    var svg = Viz("digraph { a -> b; }", "svg");
    document.getElementById("foo").innerHTML = svg;
<script>

是說不知道還支援什麼輸出 type?

viz.js 唯一的怪哏就是它沒有提供 viz.js 檔。作者把 viz.js 當作 binary 檔案…. [炸],估計是要自己跑 Makefile?不過也無所謂,直接連範例網頁,抓上頭的 viz.js 檔就可以正常執行。目前看起來都沒啥太大問題,只要你不考究畫出來的圖夠不夠好看…… [遠目]


Update v1:

要在 GWT 當中用也十分簡單,簡單到不想包一個 class 來處理 XD。首先,當然要在 host page 補上 viz.js 檔(同上),然後在 Java 中:

//JSNI 的 method
private native String genGraphViz(String dot) /*-{
    return $wnd.Viz(dot, "svg");
}-*/;

//準備一個 HTML widget,這裡直接用 UiBinder 寫了
@UiField HTML svg;

//某個神奇的角落
svg.setHTML(genGraphViz(DOC_CODE));

你看,是不是很簡單呢? [麥兜母調]


Update V2:

另外找到這個純正 GWT 的 GraphicViz project:Exagraph,不過我(還)很滿意現在的 viz.js,所以就沒有實際去試試看了……

以上簡單報告……

2011-10-27

GWT 2.4.0 需搭配 gwt-maps 1.1.1rc1

雖然這篇文章可能一兩個月後就沒啥鳥用,但是為了這點鳥事搞了一個下午,還是寫篇文章以供日後緬懷...... [遠目] (其實根本就是想點擊率吧? [指])

故事的前情提要是我想要透過 Google Maps API 作一些壞事,但是用 JavaScript 做起來實在不夠愉快,更不用說有些東西已經偷懶用 JSP 控制還是不能徹底解決問題。好吧,那就徹底 Java 到底,透過 gwt-google-api 的 Maps 來惡搞。

2009-09-17

GWT 的 Debug Panel (3rd party lib) 介紹

原文網址:http://googlewebtoolkit.blogspot.com/2009/07/introducing-debug-panel-for-gwt.html

Debug Panel 最主要的用途,是提供開發人員在 debug client 端程式碼時,一些關於 application 的效能資料。用 GWT 建立的 web application,大部分在 client 端的環境運作,這是開發人員不太能控制或存取的。Debug Panel 提供開發人員一個工具,除去 client 環境的阻礙以便於診斷問題所在、調整或加強效能以助於 application 測試。

就像所有的 application,測試及品質保證(QA)對於 GWT application 也是很重要的。也因為 GWT application 是使用者介面,所以效能測試是非常重要的。但是,在 browser 上運作的 application,要測量它的效能不是件容易的事情。那些在 client 端才變動的部份(例如 RPC, DOM 的更新)、以及 GWT 讓你不再自己撰寫 JavaScript 的狀況下,要找出效能瓶頸就有點困難了。要自動化效能測試、以及取得 RPC 精確的反應時間,就更加困難。此刻就是 Debug Panel 登場的時候啦!這是一個外掛的 library,可以輕鬆地加到 GWT application 當中。它提供你效能面的數據、理解表面之下的運作,並且將這一切自動化!

下面是 Debug Panel 的真相:

Debug Panel 展示了調用 EchoService 的統計資料、以及起始時間。很明顯的,RPC 非常快就做完了。其中最慢的部份是在等待 server 的回應,花了 121ms;serialize request 跟 deserialize response 都花了 19ms;更新 server 回傳的資料到 UI 上頭花了 2ms。這些事你會想要看到的數據。

下面是 Debug Panel 的另一個真相:

這次有點不一樣,這個 application 在 Hosted 模式下運行時,在 RPC 的過程中炸了一個 exception。當你把 application 轉譯成 JavaScript 時,stack trace 很理所當然地會是 JavaScript 的 stack trace。exception panel 是 Debug Panel 裡頭的一個延伸。GWT 的開發者可以針對自己的需求,把客制化的 panel 加到 Debug Panel。Debug Panel 提供一個 framework,讓你可以用一個輕量級的元件加到你的 application 以顯示相關的 debug 資料,並且可以傳遞相關資料給 Debug Panel,還不太會影響到執行效率。

事實上,你可以在不改任何程式碼的情況下,把 Debug Panel 掛到一個已經存在的 application。這也表示在 compile JavaScript 時不用作啥改變。你可以讓 GWT application 在處理內部 IP 時讓 Debug Panel 起作用,其他狀況下則關掉。

試試看 Debug Panel 的線上範例、也看一下 source code,你就會發現使用起來有多簡單啦。到我們在 Google Code 的主頁也可以得到更多的資訊。

2009-09-10

ColorPicker (auroris) Bug Fix

技術提供:aries

「http://code.google.com/p/auroris/」這是一個 GWT 上的 3rd party library,負責提供還不錯的 color picker 元件。不過,在實際使用的時候,卻會有「某些時候」中間那條直立漸層色條出不來的 bug。經過一番血戰之後,終於抓到了... 設定顏色的時候少一個「#」

//ColorPicker.java 的片段
    public void onClick(Widget sender) {
        if (sender == rbHue) {
            // skip
        } else if (sender == rbSaturation) {
            if (colorMode != SliderMap.Saturation) {
                colorMode = SliderMap.Saturation;
                slidermap.setColorSelectMode(SliderMap.Saturation);
                sliderbar.setColorSelectMode(SliderBar.Saturation);
                slidermap.setOverlayColor("transparent");
                sliderbar.setLayerColor("#ffffff", SliderBar.BarC);
                sliderbar.setLayerOpacity(100, SliderBar.BarD);
            }

            slidermap.setOverlayOpacity(100 - saturation);
            /* ERROR
             * sliderbar.setLayerColor(tbHexColor.getText(), SliderBar.BarD);
             */
            sliderbar.setLayerColor("#" + tbHexColor.getText(), SliderBar.BarD);

            sliderbar.setSliderPosition(256 - (int) ((new Integer(saturation)
                    .floatValue() / 100) * 256));
            slidermap
                    .setSliderPosition(
                            (int) ((new Integer(hue).floatValue() / 360) * 256),
                            256 - (int) ((new Integer(brightness).floatValue() / 100) * 256));
        } else if (sender == rbBrightness) {
            // skip
        } else if (sender == rbRed) {
            // skip
        } else if (sender == rbGreen) {
            // skip
        } else if (sender == rbBlue) {
            // skip
        }

        if (colorMode == SliderMap.Red || colorMode == SliderMap.Green
                || colorMode == SliderMap.Blue) {
            // skip
        }
    }

其實造成「某些時候」才會出問題的原因不在這裡,而是 HTML 碼有沒有這個「
<DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">」。拿掉的話,錯誤也就不會發生,不過,不怎麼建議用這招就是了。

測試環境:
  • GWT 1.7
  • FireFox, Chrome(IE 不會出問題)