Hi Mark

Thanks for making it work

You should actually change it from MultipartBody to Attachment - the latter represents an individual part, the former the whole multipart request - you'd use if you wanted to have only a single parameter to deal with the multipart request (instead of 3 ones in this case).

As far as Attachment is concerned, you'd use Attachment only if you need access to the headers of the individual part...Also if you had a Content-Type for the first part set, then you'd be able to use @Multipart("json") Order order, etc


Sergey




On 27/10/15 14:25, Mark Streit wrote:
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/




--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Reply via email to