2010年8月6日

Windows環境執行Groovy/Groovlet/GSP的編碼問題

在正體中文的Windows系統,預設編碼格式為MS950,Groovy會參考這個預設值,並假設所讀到的Groovy/Groovlet/GSP程式碼都是MS950編碼,基本上儲存成BIG5/ASCII的程式碼檔案,大致上都可以順利讀取,但遇到UTF-8編碼的程式碼檔案,有中文字出現的地方,Groovy還是當作MS950來處理,這時候會出現類似以下的錯誤訊息:

2010/8/6 下午 02:17:18 org.apache.catalina.core.ApplicationContext log
資訊: groovy.util.ScriptException: Could not parse scriptName: /register.groovy
2010/8/6 下午 02:17:20 org.apache.catalina.core.ApplicationContext log
嚴重的: An error occurred processing the request
java.lang.RuntimeException: groovy.util.ScriptException: Could not parse scriptName: /register.groovy
at groovy.servlet.GroovyServlet$1.call(GroovyServlet.java:123)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:147)
at groovy.servlet.GroovyServlet.service(GroovyServlet.java:128)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:619)
Caused by: groovy.util.ScriptException: Could not parse scriptName: /register.groovy
at groovy.util.GroovyScriptEngine.updateCacheEntry(GroovyScriptEngine.java:318)
at groovy.util.GroovyScriptEngine.createScript(GroovyScriptEngine.java:398)
at groovy.util.GroovyScriptEngine.run(GroovyScriptEngine.java:385)
at groovy.servlet.GroovyServlet$1.call(GroovyServlet.java:119)
... 15 more
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, /register.groovy: 133: expecting ''', found '\n' @ line 133, column 23.
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:296)
at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:143)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:113)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:125)
at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:352)
at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:80)
at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:248)
at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:143)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:772)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:438)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:277)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:248)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:243)
at groovy.util.GroovyScriptEngine.updateCacheEntry(GroovyScriptEngine.java:316)
... 18 more

看到紅色的那段字了嗎?Java的錯誤訊息一向都是這樣落落長,只要找重點即可,從錯誤訊息大致上可以""出,就是編碼問題惹得禍。

最快速的解決方法,也是個奧步,就是在啟動JVM之前,加個JAVA_OPTS環境變數設定。
JAVA_OPTS=-Dfile.encoding=utf-8 -Duser.language=en

用file.encoding將預設的檔案編碼指定為UTF-8,而這個奧步引發另一個問題,就是從終端機輸出的所有Java Log資料,有中文的部分就變成亂碼;這樣是另一個故事了,因為M$ Windows的終端機,也假設它執行的程式一定會輸出MS950編碼文字,所以這時候Java程式輸出的UTF-8編碼,又被誤認是MS950的終端機輸出成亂碼。所以再來一個奧步,乾脆將user.language設定為en(英文),Log的中文變少就看不到亂碼了。

其實Java對編碼系統的支援算是挺完善,只是在開發過程中,必須留意不同編碼混在一起可能造成的問題,經常有很複雜的情況,例如讀取BIG5編碼的檔案,在程式中轉為UTF-8處理,最後再輸出時又要以MS950顯示;對CJK(中日韓文)的開發者來說,編碼的問題比較棘手,所以通常在開發階段就會考慮到文字編碼的處理,而EN(英文)系的開發者,就可能忽略了在世界上還有其他使用複雜文字的人類,例如像Sakai這樣大的project,居然有一堆官方發布的程式,只要遇到中文就送你error msg。

身為中文世界的軟體開發者,不懂編碼系統是件誤人誤己的事,如果到了2010年還搞不懂編碼的處理,先讀讀約耳(他是位ABC)的這篇文章《The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)》。

沒有留言:

張貼留言

lyhcode by lyhcode
歡迎轉載,請務必註明出處!