Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Posting multipart form data to seam+RESTeasy fails marshalling to InputStream

I'm trying to post image data to a seam+RESTeasy endpoint and I'm getting a very cryptic error during JBoss startup. The HTTP request I'm sending has a content-type of multipart/form-data which has a single image/jpeg part with name "attachment". My service method looks like this:

@POST
@Path("uploadSymptomsImage/{appointmentGUID}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json")
public String uploadSymptomsImage( @FormParam("attachment") InputStream fileInputStream,
                                   @PathParam("appointmentGUID") String strAppointmentGUID )
{ ...

The error that I get is during startup:

Caused by: java.lang.RuntimeException: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.FormParam("attachment") on public java.lang.String com....AppointmentRestService.uploadSymptomsImage(java.io.InputStream,java.lang.String) for basetype: java.io.InputStream
at org.jboss.resteasy.core.StringParameterInjector.initialize(StringParameterInjector.java:206) [:]
at org.jboss.resteasy.core.StringParameterInjector.<init>(StringParameterInjector.java:57) [:]
at org.jboss.resteasy.core.FormParamInjector.<init>(FormParamInjector.java:22) [:]

My understanding was that media types could be automatically marshalled to InputStream. I've also tried java.io.File, java.io.Reader - both with same error. When I replace with byte[] or String I get a zero length array, or null as the parameter value.

How would you go about debugging this? Also, is it possible to access the raw request or pre-marshalled values?

Any suggestions here would be greatly appreciated.

like image 299
tyler Avatar asked Nov 14 '22 03:11

tyler


1 Answers

You should retrieve the contents using MultipartFormDataInput. See the following example:

@POST
@Path("uploadSymptomsImage/{appointmentGUID}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json")
public String uploadSymptomsImage(@PathParam("appointmentGUID") String strAppointmentGUID,
                               MultipartFormDataInput formData) {

    Map<String, List<InputPart>> formDataMap = formData.getFormDataMap();

   List<InputPart> attachments = formDataMap.get("attachment");
   for(InputPart attachment : attachments) {
        String fileName = extractFilename(attachment);
        if(fileName.isEmpty()) continue;
        InputStream in = attachment.getBody(new GenericType<InputStream>() {});
        // Interact with stream
   }

    // Respond
}

The extractFilename method is a helper method I wrote:

private static String extractFilename(final InputPart attachment) {
    Preconditions.checkNotNull(attachment);
    MultivaluedMap<String, String> headers = attachment.getHeaders();
    String contentDispositionHeader = headers.getFirst("Content-Disposition");
    Preconditions.checkNotNull(contentDispositionHeader);

    for(String headerPart : contentDispositionHeader.split(";(\\s)+")) {
        String[] split = headerPart.split("=");
        if(split.length == 2 && split[0].equalsIgnoreCase("filename")) {
            return split[1].replace("\"", "");
        }
    }

    return null;
}
like image 169
Jan-Willem Gmelig Meyling Avatar answered Dec 11 '22 04:12

Jan-Willem Gmelig Meyling