2010年2月12日金曜日

[Lift] Lift2.0-scala280で日本語テンプレートが使えない

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

2010-02-25追記

Lift 2.0-M3で治るそうです(google-group)。テンプレートは必ずutf-8で!

元記事

先日、せっかくだから最新を使おうと、Lift2.0-scala280(beta)に手を出してみました。API周りの修正はarchetype-basicで生成しなおしたプロジェクトを元にマージし、ビルドできるようになったと思いきや、Lift1.0.2では動いてたページが、以下のエラーで動作しなくなりました。
Message: java.nio.charset.UnmappableCharacterException: Input length = 2
       java.nio.charset.CoderResult.throwException(CoderResult.java:261)
       sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:319)
       sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
       java.io.InputStreamReader.read(InputStreamReader.java:167)
       java.io.BufferedReader.fill(BufferedReader.java:136)
       java.io.BufferedReader.read(BufferedReader.java:157)
       scala.io.BufferedSource$$anonfun$1$$anonfun$apply$1.apply(BufferedSource.scala:29)
       scala.io.BufferedSource$$anonfun$1$$anonfun$apply$1.apply(BufferedSource.scala:29)
       scala.io.Codec.wrap(Codec.scala:65)
       scala.io.BufferedSource$$anonfun$1.apply(BufferedSource.scala:29)
       scala.io.BufferedSource$$anonfun$1.apply(BufferedSource.scala:29)
       scala.collection.Iterator$$anon$13.next(Iterator.scala:145)
       scala.collection.Iterator$$anon$24.hasNext(Iterator.scala:435)
       scala.collection.Iterator$$anon$19.hasNext(Iterator.scala:326)
       scala.io.Source.hasNext(Source.scala:209)
       net.liftweb.util.PCDataXmlParser$$anonfun$apply$2$$anonfun$apply$4.apply(PCDataMarkupParser.scala:184)

スタックトレースの示すPCDataMarkupParser.scala:184近辺を見てみたところ、scala.io.Source.fromInputStream(in)が使われていますが、Scala2.7.7と2.8.0で、エンコードを指定しなかった場合の動作が変わっています。2.7.7では、utf-8が使われます(*1)が、2.8.0だとSource.fromInputStreamは新しく導入されたCodecを引数に取るようになり、省略した場合はCodec.defaultが使用されます(*2)。

  1. 2.7.7のscaladoc: same as BufferedSource.fromInputStream(is, "utf-8", Source.DefaultBufSize)
  2. 2.8.0-Betaのscaladoc: codec (implicit) a scala.io.Codec specifying behavior (defaults to Codec.default)

上記APIの仕様変更により、日本語Windowsなうちの環境だとutf-8のテンプレートをMS932で読もうとして失敗しているわけですね。

Scala2.8.0のライブラリの、Codec.defaultのソースを見てみると、
def default = apply(Charset.defaultCharset)
としているだけ(Charsetはjava.nio.charset.Charset)なので、JVMのシステムプロパティで-Dfile.encodingを設定してやればOKそうです。Mavenでjettyを起動しているので、MVN_OPTSに-Dfile.encoding=utf-8を追加したら問題なく動きました。

関連Tweet 2010-02-02 20:06:36~

運用環境だとそう簡単にJVMのシステムプロパティなど変えられないと思うので、どこかでテンプレートのエンコーディングを指定するか、もう必ずutf-8で読んでくれるかしれくれないと困りますね。LiftのMLに投げました。

追記

MVN_OPTSで-Dfile.encoding=utf-8にしてNetBeansからrun:jettyで起動すると、コンソールの日本語が化けます。おそらくNetBeansも自身のJVMのfile.encoding(この場合はMS932)を使用してコンソールに出力しているためと思われます。

0 件のコメント:

コメントを投稿