RESTEasyの話。
リソースクラスを実装して、JSONレスポンスを返そうとした時に、アプリケーションがUTF-8でなくShift-JIS形式のJSON文字列を返してしまう現象に出くわした(JBoss 5.1.0GA, Seam 2.2)。
なお、JSONエンコーディングにはJSONICを利用。ただし、JSONICが提供しているRESTサーブレットは未使用。
実装したメソッドの要点だけ抜き出すとこんな感じ(曖昧)。
@GET @Produces("application/json;charset=UTF-8") @Path("/items") public Response getItems() { List<Item> itemList = ... // データ取得 String jsonText = JSON.encode(itemList); ResponseBuilder builder = Response.ok(). entity(jsonText). header("Content-Type", "application/json; charset=utf-8"); return builder.build(); }
で、上記を含めたアプリをデプロイして、ブラウザからhttp://xxx/seam/resource/rest/hoge/itemsにアクセスして、取得できる値を確認してみる。
そすると、CentOSの場合は、ちゃんとUTF-8で表示されるのに、WindowsだとShift-JISで取得してしまう。
ちなみに、Jerseyで試したちょんプロだとWindowsでも問題なかったので、RESTEasyの場合、OSのデフォルトエンコーディング使ってる不具合?とか推測しつつも、うまく解決ができないでいた。
で、このトピックを参考に、StreamingOutputを使うようにして再実装。
@GET @Produces("application/json;charset=UTF-8") @Path("/items") public Response getItems() { List<Item> itemList = ... // データ取得 final String jsonText = JSON.encode(itemList); StreamingOutput streamingOutput = new StreamingOutput() { public void write(OutputStream outputStream) { PrintStream writer = new PrintStream(outputStream, true, "UTF-8"); writer.print(jsonText); } }; ResponseBuilder builder = Response.ok(). entity(streamingOutput). header("Content-Type", "application/json; charset=utf-8"); return builder.build(); }
これで表示できた。すごく無理矢理な感じがする。にしてもentityにStreamingOutputをそのまま突っ込んで問題なく動作するのが違和感。
RESTEasyで、XML以外のレスポンスを返したい場合、HTTPヘッダとかを柔軟にコントロールしたいこととかを考えると、メソッドの戻りはResponseで統一しとくのが楽なのかな。。