JBossのRESTEasyにおけるMultipart Requestの文字化け対策

  • 6
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

仕事で若干困ったのと、文字化け系の現象なのだが、同内容の対応についての日本語ページがまったく引っ掛からなかったので、メモしておく.

背景

やろうとしていたことは、↓.

  • multipart/form-dataでJAX-RS(JBoss EAP 6.2, RestEASY)にファイルをUpload.
  • フォームデータには日本語を許可.

コードのイメージは下記な感じだ.

FileResource.java
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;

@Path("/file")
public class FileResource {

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response create(@MultipartForm UploadData uploadData){

        String fileName = uploadData.getFileName(); // ★ こいつが文字化!
        // 色々処理...
        return Response.ok().build();
    }
}
UploadData.java
public class UploadData implements Serializable{
    private String fileName;
    private byte[] fileBody;
    public String getFileName() {
        return fileName;
    }
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
    public byte[] getFileBody() {
        return fileBody;
    }
    public void setFileBody(byte[] fileBody) {
        this.fileBody = fileBody;
    }


}   

RESTEasyの拡張アノテーション@MultipartFormでデータの取得をしようとするも、日本語を含む項目が悉く文字化けする.

原因

仕方なく、multipart関連のProvider実装(org.jboss.resteasy:resteasy-multipart-provider:2.3.6-final)のソースを読んでみたところ、org.jboss.resteasy.plugins.providers.multipart.InputPart のJavadocに下記が書いてあった.

    /**
     * If there is a content-type header without a charset parameter, charset=US-ASCII
     * is assumed.
     * <p>
    * This can be overwritten by setting a different String value in
    * {@link org.jboss.resteasy.spi.HttpRequest#setAttribute(String, Object)}
    * with this ("resteasy.provider.multipart.inputpart.defaultCharset")
    * String as key. It should be done in a
    * {@link org.jboss.resteasy.spi.interception.PreProcessInterceptor}.
    * </p>
     */
    static final String DEFAULT_CHARSET_PROPERTY = "resteasy.provider.multipart.inputpart.defaultCharset";

要は、「multipartの各partについて、content-type=○○; charset=... のようなヘッダが無い場合, ProviderはUS-ASCIIで文字コード変換するよ」という内容だ.

対応方法

JavaDocにも書いてある通り、org.jboss.resteasy.spi.HttpRequest#setAttribute"resteasy.provider.multipart.inputpart.defaultCharset"をセットする方法でやってみたところ、無事解決(なお、後からこのキー名でググってみたら、JavaDocだけでなく、RESTEasy本家のドキュメントにも記載がありました...).

ContentTypeSetterPreProcessorInterceptor.java
import org.jboss.resteasy.plugins.providers.multipart.InputPart;

@Provider
@ServerInterceptor
public class ContentTypeSetterPreProcessorInterceptor implements
        PreProcessInterceptor {

    public ServerResponse preProcess(HttpRequest request,
            ResourceMethod method) throws Failure, WebApplicationException {
        request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, "UTF-8");
        return null;
    }

}

PreProcessInterceptorhttp://docs.jboss.org/resteasy/docs/2.3.6.Final/userguide/html_single/index.html#PreProcessInterceptors にもある通り、RESTEasyのリクエスト時に HttpRequestへの拡張ポイントとして利用できる. @Providerが付与されていれば、勝手にJBossがInterceptorとして登録してくれるため、特に設定ファイル等の記載は不要.

参考リンク