仕事で若干困ったのと、文字化け系の現象なのだが、同内容の対応についての日本語ページがまったく引っ掛からなかったので、メモしておく.
背景
やろうとしていたことは、↓.
-
multipart/form-data
でJAX-RS(JBoss EAP 6.2, RestEASY)にファイルをUpload. - フォームデータには日本語を許可.
コードのイメージは下記な感じだ.
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();
}
}
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本家のドキュメントにも記載がありました...).
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;
}
}
PreProcessInterceptor
は http://docs.jboss.org/resteasy/docs/2.3.6.Final/userguide/html_single/index.html#PreProcessInterceptors にもある通り、RESTEasyのリクエスト時に HttpRequest
への拡張ポイントとして利用できる. @Provider
が付与されていれば、勝手にJBossがInterceptorとして登録してくれるため、特に設定ファイル等の記載は不要.