Search code examples
restglassfishjax-rsmultipartjava-ee-7

Consuming muiltipart POST data in JAX-RS REST Service


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


Solution

  • 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?