読者です 読者をやめる 読者になる 読者になる

Windows環境にてRESTEasyを使ってJSONレスポンスを返すとUTF-8にならない件

Java JBoss

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で統一しとくのが楽なのかな。。