Thanks for getting back to me Sergey. I meant to update the email post... It appears that I have found the problem (on my end):
I changed the annotated method in the interface FROM THIS syntax (failed) ... @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) @Path("/ordermanagement/{CUSTID}/orders") public Response addOrderDocument(@Multipart("json") String json, @Multipart("orderfile") InputStream contentStream, @FormParam("fileInfo") ContentDisposition fileInfo, @Context UriInfo info, @QueryParam("$filter") String filter) throws RESTServiceException; TO this syntax: @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) @Path("/ordermanagement/{CUSTID}/orders") public Response addOrderDocument(@Multipart("json") String json, @Multipart("*orderfile*") *MultipartBody* *orderfile*, @Context UriInfo info, @QueryParam("$filter") String filter) throws RESTServiceException; And now, code like this, that's used in the Implemented method... WORKS ! :-) : public Response addOrderDocument(String json, *MultipartBody* *orderfile*, UriInfo info, String filter) throws RESTServiceException { LOGGER.trace("entry params: json = [{}], search = [{}], filter = [{}]", json, filter); Attachment file = orderfile.getAttachment("*orderfile*"); if ( file != null) { contentStream=file.getObject(InputStream.class); LOGGER.trace("file.getContentType = [{}]", file.getContentType()); LOGGER.trace("file.getContentDisposition = [{}]", file.getContentDisposition().toString()); LOGGER.trace("contentStream = [{}]", contentStream); } The LOGGER output showed what I expected, including the stream of binary characters in the contentStream ... It's just that with Multipart POST, the 2 stacks seem to vary somewhat in the required classes and syntax used... but both appear to accomplish the same thing of course. The key was defining the *orderfile* as a *MultipartBody* type and naming it correctly in the @Multipart() annotation so the Attachment instance could be pulled from the object received... I had to add these imports: import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; Regards, Mark On Tue, Oct 27, 2015 at 9:45 AM, Sergey Beryozkin <sberyoz...@gmail.com> wrote: > Hi Mark > > Sorry for a delay, > > I'm not seeing a 'fileinfo' part in the payload which works with Jersey, > where exactly does it have a 'fileinfo' from ? Or is it a convention used > to refer to Content-Disposition of the very last part ? > > Cheers, Sergey > > On 25/10/15 13:37, Mark Streit wrote: > >> Hello >> >> We have a deployed set of JAX-RS endpoints which work fine under Jersey >> and >> include both GET and POST annotated methods. >> >> We are looking to move from Jersey to CXF with this and @GET methods >> appear to be fine. However @POST methods are presenting some problems. >> >> (Note: We place annotations on the interface and not the implementation >> classes directly - this works in BOTH cases - the WADL returned appears >> correct) >> >> We are also using POSTMAN for the test, so it generates the form/mime >> boundaries automatically. I've also omitted the HTTP Headers and binary >> content for brevity. >> >> *The Jersey case: Relevant annotations in yellow: - these appear to be >> Jersey-specific* (all others are standard JAX-RS annotations) >> >> >> @POST >> @Consumes(MediaType.MULTIPART_FORM_DATA) >> @Produces(MediaType.APPLICATION_JSON) >> @Path("/ordermanagement/{CUSTID}/orders") >> public Response addOrder(@FormDataParam("json") String json, >> @FormDataParam("orderfile") >> InputStream contentStream, @FormDataParam("fileInfo") >> FormDataContentDisposition fileInfo, @Context UriInfo info, >> @PathParam(AppConstants.CUSTID) String CUSTID, >> @QueryParam(AppConstants.SOURCE_APP_ID_PARAM) String srcAppId, >> @QueryParam(AppConstants.SOURCE_APP_FEATURE_ID_PARAM) String >> srcAppFeatureId) throws RESTServiceException; >> >> >> *Example of POSTMAN test that WORKS SUCCESSFULLY for this case* >> >> POST >> >> /services/core/orderprocess/ordermanagement/22334455/orders?srcAppId=orderService&srcAppFeatureId=creation >> HTTP/1.1 >> Host: localhost:8080 >> >> ### MOST HEADERS-REMOVED-FOR-CLARITY ### >> >> Cache-Control: no-cache >> Postman-Token: db5a119a-e885-4bfd-14ae-8bac119845bd >> Content-Type: multipart/form-data; >> boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> Content-Disposition: form-data; name="json" >> >> { "displayName": "OrderxTest", "originalFileName": "OrderxTest.pdf", >> "fileName": "OrderxTest.pdf", "OrderumentType": "pdf", >> "OrderumentStatus": "CLEAR", "attachmentType": "Company", "category": >> "DRAFT", "subcategory": "DRAFT", "keywords": "", "notes": [], >> "fileSize": 163361, "uploadState": "PROGRESS", "metadataState": >> "INCOMPLETE", "uploadFile": {}, "nextOrder": "" } >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> Content-Disposition: form-data; name="orderfile"; >> filename="OrderxTest.pdf" >> Content-Type: application/pdf >> >> >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> >> ### BINARY DATA STREAM REMOVED ### >> >> *The POST is processed successfully and we get back a HTTP 202* >> >> >> >> *The CXF case: Relevant annotations in yellow: - these appear to be >> CXF-specific, everything is the same except changing what we believed were >> the required annotation changes* >> >> *@POST* >> *@Consumes(MediaType.MULTIPART_FORM_DATA)* >> *@Produces(MediaType.APPLICATION_JSON)* >> *@Path("/ordermanagement/{CUSTID}/orders")* >> *public Response addOrderument(@Multipart("json") String json, >> @Multipart("orderfile") InputStream contentStream, @FormParam("fileInfo") >> ContentDisposition fileInfo, @Context UriInfo info, @QueryParam("$filter") >> String filter) throws RESTServiceException;* >> >> >> >> *Example of POSTMAN test that FAILS for this case* >> >> >> POST >> >> /services/core/orderprocess/ordermanagement/22334455/orders?srcAppId=orderService&srcAppFeatureId=creation >> HTTP/1.1 >> Host: localhost:8080 >> >> ### MOST HEADERS-REMOVED-FOR-CLARITY ### >> >> Cache-Control: no-cache >> Postman-Token: db5a119a-e885-4bfd-14ae-8bac119845bd >> Content-Type: multipart/form-data; >> boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> Content-Disposition: form-data; name="json" >> >> { "displayName": "OrderxTest", "originalFileName": "OrderxTest.pdf", >> "fileName": "OrderxTest.pdf", "OrderumentType": "pdf", >> "OrderumentStatus": "CLEAR", "attachmentType": "Company", "category": >> "DRAFT", "subcategory": "DRAFT", "keywords": "", "notes": [], >> "fileSize": 163361, "uploadState": "PROGRESS", "metadataState": >> "INCOMPLETE", "uploadFile": {}, "nextOrder": "" } >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> Content-Disposition: form-data; name="orderfile"; >> filename="OrderxTest.pdf" >> Content-Type: application/pdf >> >> >> ----WebKitFormBoundary7MA4YWxkTrZu0gW >> >> ### BINARY DATA STREAM REMOVED ### >> >> >> The call fails with the following stack trace clearly something involving >> the "multi-part" element processing... I am assuming we have made an error >> in using what were believed to be the CXF-equivalent annotations. >> >> java.lang.RuntimeException: *Invalid URL encoding: not a valid digit >> (radix >> 16): 80* >> * org.apache.cxf.common.util.UrlUtils.digit16(UrlUtils.java:114)* >> * org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:94)* >> * org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:66)* >> * org.apache.cxf.common.util.UrlUtils.urlDecode(UrlUtils.java:121)* >> * org.apache.cxf.jaxrs.utils.HttpUtils.urlDecode(HttpUtils.java:94)* >> * >> >> org.apache.cxf.jaxrs.utils.FormUtils.populateMapFromMultipart(FormUtils.java:230)* >> * >> >> org.apache.cxf.jaxrs.utils.JAXRSUtils.processFormParam(JAXRSUtils.java:956)* >> * >> >> org.apache.cxf.jaxrs.utils.JAXRSUtils.createHttpParameterValue(JAXRSUtils.java:877)* >> * >> >> org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:837)* >> * >> >> org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:787)* >> >> >> org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212) >> >> org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77) >> >> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) >> >> org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) >> >> org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251) >> >> org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) >> >> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) >> >> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) >> >> org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:171) >> >> org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:293) >> >> org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:212) >> javax.servlet.http.HttpServlet.service(HttpServlet.java:646) >> >> I did try changing the >> >> @FormParam("fileInfo") ContentDisposition fileInfo part of the annotated >> method to >> >> >> @Multipart("fileInfo") ContentDisposition fileInfo >> >> >> and this time the error was quite different, appears the MIME boundary is >> confusing things ... or we clearly are not using the correct annotations >> on >> this: >> >> Oct 25, 2015 9:10:08 AM >> org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils getMultipart >> >> WARNING: No multipart with content id fileInfo found, request content type >> : multipart/form-data;boundary=----WebKitFormBoundarysJRabRa4EZMpZwwB >> >> Oct 25, 2015 9:10:08 AM >> org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse >> >> WARNING: javax.ws.rs.BadRequestException: HTTP 400 Bad Request >> >> at org.apache.cxf.jaxrs.utils.SpecExceptions.toBadRequestException( >> SpecExceptions.java:84) >> >> at org.apache.cxf.jaxrs.utils.ExceptionUtils.toBadRequestException( >> ExceptionUtils.java:114) >> >> at org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getMultipart( >> AttachmentUtils.java:143) >> >> at org.apache.cxf.jaxrs.provider.MultipartProvider.readFrom( >> MultipartProvider.java:169) >> >> at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader( >> JAXRSUtils.java:1340) >> >> at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody( >> JAXRSUtils.java:1291) >> >> at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter( >> JAXRSUtils.java:824) >> >> at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters( >> JAXRSUtils.java:787) >> >> at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest( >> JAXRSInInterceptor.java:212) >> >> at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage( >> JAXRSInInterceptor.java:77) >> >> >> Trying to understand how, if possible, to only change the annotations on >> the method signature and still have the POST operation work under CXF. We >> have managed to have the GET operations working fine, but there are far >> less differences the GET operations are using mostly stack independent and >> rely on standard JAX-RS annotations anyway. >> >> >> Any insight from CXF experts would be appreciated... >> >> Thanks >> >> Mark >> >> > > -- > Sergey Beryozkin > > Talend Community Coders > http://coders.talend.com/ >