1

I have a jax-rs REST service, using JEE 7 (deployed in glassfish), which has a method to process HTTP POST on the resource:

@POST
@Path(value="{dId}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response sendStatus(@Context HttpServletRequest request)

I try to extract the multipart data as:

Collection<Part> parts = request.getParts();
if(parts==null || parts.isEmpty()){
        lg.warn("Empty/non-existent parts in request body!");
        return sendBadRequestError(sp);
}

I then try to simulate a client multipart POST request, using RestClient(from wiztools.org), with atleast 2 parts of different content-types ( boundary delimiter is automatically set by the RESTClient tool).

I verify in wireshark that its a proper request that is sent from the RESTClient( no malformed packet etc).

However, all the request seems to hit the block containing the Empty/non-existent parts in request body message, indicating there were no parts found in the request.

I searched around in Stackoverflow many times before posting, and all the examples/solutions relate to use-case where one is uploading a file/image, which is not the case am dealing with.

My rest service just consumes a multipart request, which can consist of one part with JSON data, another part with simple string or other JSON data.

Is there something am missing - please help?.Is there someother technique to parse the multipart data that hits a REST service?

Please advice.

Thanks. J

Javy
  • 21
  • 5
  • 1
    Chapter 9 of JSR-339 states which types can be used with `@Context`. Does it work if you use `@FormParam` instead? Or using the Request (http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Request.html) interface instead of HttpServletRequest? – Martijn Burger Sep 27 '15 at 22:30
  • 1
    I imagine Jersey has already read the input stream. Use the Jersey multipart APIs instead of directly accessing the HttpServletRequest. See [Multipart Support](https://jersey.java.net/documentation/latest/media.html#multipart) – Paul Samsotha Sep 28 '15 at 09:14
  • Thanks MartijnBurger and peeskillet for your suggestions. Let me try these options and get back. – Javy Sep 28 '15 at 13:17
  • @MartijnBurger: I found the Request (docs.oracle.com/javaee/7/api/javax/ws/rs/core/Request.html) API's not so easy to use, and at first glance did not apparently seem to mechanism to extract the multipart body entities in a easy way. Not sure if it was the intent of the API too. I did not use @ FormParam, but used org.glassfish.jersey.media.multipart.FormDataParam. The problem with either is that its not generic to use if we do not know the number of body parts ( in a multipart request) that can be expected from a request. Thanks for your time - the pointers helped me think differently! – Javy Sep 28 '15 at 20:08

1 Answers1

1

Thanks to pointers from @peeskillet, I used the Jersey multipart API to get the handle to the multipart entities.

Just so that it may help others bumping into the same problem, am listing the complete solution:

  1. Enable "MultiPart" capability for your app in the container. This is necessary for availability of the required readers/writers. How to do this is clearly articulated in Jersey 2 injection source for multipart formdata
  2. The resource method then is defined as

    @POST
    @Path(value="{dId}")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendStatus(FormDataMultiPart multipart){
    ....
    ...
       Map<String, List<FormDataBodyPart>> parts = multipart.getFields();
       if(parts==null || parts.isEmpty()){
           lg.warn("Empty/non-existent parts in request body!");
           return sendBadRequestError(sp);
       }
    
       for(List<FormDataBodyPart> p: parts.values()){
             FormDataBodyPart bp = p.get(0);
             lg.info("\t body part name {}",bp.getName());
             lg.info("\t body part value {}",bp.getValue());            
              ....//do your real stuff here
        }
    
     }
    

And bingo it works!.

Also a side note: when using the RESTClient GUI tool, make sure you don't explicitly set the Content-Type and Boundary, since the tool set its automatically.

Hope this helps someone.

ps: How do I vote for peeskillet's answer?

Community
  • 1
  • 1
Javy
  • 21
  • 5
  • 1
    Yes. There are implementations (Jersey, Apache CXF) of the JAX-RS specification that implement a proprietary solution for this. The question was however, how to do it with JAX-RS. As you can see in this ticket, it is a request that is waiting for implementation https://java.net/jira/browse/JAX_RS_SPEC-413 – Martijn Burger Sep 29 '15 at 06:50
  • 1
    Ps: Look for and ask these questions at meta.stackoverflow.com You need a reputation of at least 15 to upvote a comment. I upvoted your question and answer, it should give you enough to upvote on comments. – Martijn Burger Sep 29 '15 at 06:51