Apache CXF REST multipart upload, encoding exception

cxf, rest

Solution

The issue got solved on the Apache CXF mailing list by Sergey Beryozkin.

To summarize it:

What happens with this declaration is that the form payload processor assumes the last parameter being just one more plain multipart/form-data parameter. When you have a 'mixed' multipart/form-data payload, containing simple String name/values pairs, alongside the binary parts, it is better to avoid using @FormParam or @Multipart annotations and only use a MultipartBody input parameter - it will provide a type-safe access to all the individual parts.

Replacing @FormParam with @Multipart should fix the issue (as an alternative to introducing MultipartBody), however the mix-up of @FormParam & @Multipart should ideally work too. This issue will be checked.

I choosed replacing @FormParam with @Multipart and this worked.

Problem

I want to upload a file using multipart form data and have problems with URLDecoder. The service code follows: ``` @POST @Path("/document") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response storeTravelDocument( @Context UriInfo uriInfo, @FormParam(value = "IDNR") String idnr, @FormParam(value="DOCNR") String documentNr, @FormParam(value="ISSUE_DATE") String issueDate, @Multipart(value = "image", type="image/jpeg") InputStream pictureStream) {.. ``` I tested with three clients, for example rest-assured: ``` given(). formParam("IDNR", "A000000A"). formParam("DOCNR", "00001"). formParam("ISSUE_DATE", "14.06.2010"). multiPart("image", new File(picturePath), "image/jpeg"). expect(). statusCode(Response.Status.CREATED.getStatusCode()). when(). post("/document"); ``` or HttpClient: ``` // build mulitpart entity MultipartEntity entity = new MultipartEntity(); entity.addPart("IDNR", new StringBody("A000000A")); entity.addPart("DOCID", new StringBody("00001")); entity.addPart("ISSUE_DATE", new StringBody("14.06.2010")); FileBody fileBody = new FileBody(new File(picturePath), "image/jpeg"); entity.addPart("image", fileBody); // build post request String uri = System.getProperty("service.url") + "/document"; HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(uri); httpPost.setEntity(entity); // execute request HttpResponse response = httpClient.execute(httpPost); int code = response.getStatusLine().getStatusCode(); // validate assert code == Response.Status.CREATED.getStatusCode(); ``` in all cases I receive the following exception: ``` in escape (%) pattern - For input string: "¬ " at java.net.URLDecoder.decode(URLDecoder.java:192) ~[na:1.7.0_03] at org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:55) ~[cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:63) ~[cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.HttpUtils.urlDecode(HttpUtils.java:81) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.FormUtils.populateMapFromMultipart(FormUtils.java:170) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processFormParam(JAXRSUtils.java:746) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.createHttpParameterValue(JAXRSUtils.java:667) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:625) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:238) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262) [cxf-api-2.6.0.jar:2.6.0] ... 25 common frames omitted 2012-05-10 12:07:54,873 [http-bio-8080-exec-5] ERROR org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver - Error occurred during error handling, give up! org.apache.cxf.interceptor.Fault: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "¬ " at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:75) ~[cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:322) [cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:122) [cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:211) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:213) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:129) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:187) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:110) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) [servlet-api.jar:na] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:166) [cxf-rt-transports-http-2.6.0.jar:2.6.0] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [catalina.jar:7.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.27] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) [catalina.jar:7.0.27] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) [catalina.jar:7.0.27] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [catalina.jar:7.0.27] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) [catalina.jar:7.0.27] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) [catalina.jar:7.0.27] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) [catalina.jar:7.0.27] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [catalina.jar:7.0.27] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) [catalina.jar:7.0.27] at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999) [tomcat-coyote.jar:7.0.27] at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565) [tomcat-coyote.jar:7.0.27] at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) [tomcat-coyote.jar:7.0.27] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [na:1.7.0_03] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [na:1.7.0_03] at java.lang.Thread.run(Thread.java:722) [na:1.7.0_03] Caused by: java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "¬ " at java.net.URLDecoder.decode(URLDecoder.java:192) ~[na:1.7.0_03] at org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:55) ~[cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:63) ~[cxf-api-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.HttpUtils.urlDecode(HttpUtils.java:81) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.FormUtils.populateMapFromMultipart(FormUtils.java:170) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processFormParam(JAXRSUtils.java:746) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.createHttpParameterValue(JAXRSUtils.java:667) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:625) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:238) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89) ~[cxf-rt-frontend-jaxrs-2.6.0.jar:2.6.0] at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262) [cxf-api-2.6.0.jar:2.6.0] ... 25 common frames omitted ``` I understand that CXF tries to decode my file (the picture) and throws an exception because of invalid characters, but I would like to prevent this decoding. The file should just be transmitted as a UTF-8 stream, unchanged and not decoded. Can anyone help me?

Original source