2

I'm working on a REST application hosted on a Liberty server that should allow support for file upload. As a part of this POST request, I'd like to allow the user to specify a few things with Form parameters. Despite using the example from IBM here, I can't quite get it to work. I can retrieve information related to the uploaded File using headers (like in the example). But when I try the same method to retrieve information about the headers, the only thing available is the name of the fields, but not their values.
I'm also trying to maintain support for Swagger..
Here's a snippet of my code:

@ApiOperation("Upload Source Code to Build")
@POST
@Path("/")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.MULTIPART_FORM_DATA)
@ApiResponses({
    @ApiResponse(code = 200, message= "OK", response=String.class)})
@ApiImplicitParams({
    @ApiImplicitParam(
            name="source", 
            value = "Source File", 
            required = true, 
            dataType = "java.io.File", 
            paramType = "form", 
            type="file"),
    @ApiImplicitParam(
            name="archive_name", 
            value = "Name of File to Retrieve", 
            required = true, 
            dataType = "java.lang.String", 
            paramType = "form", 
            type="string"),
    @ApiImplicitParam(
            name="build_command", 
            value = "Command to Run", 
            required = true, 
            dataType = "java.lang.String", 
            paramType = "form", 
            type="string")})
public Response uploadFileBuildArchive(
        @ApiParam(hidden=true) IMultipartBody multipartBody,
        @Context UriInfo uriInfo) throws IOException {
    List<IAttachment> attachments = multipartBody.getAllAttachments();
    InputStream stream = null;
    Iterator<IAttachment> it = attachments.iterator();
    IAttachment attachment = it.next();

    if (attachment == null)
        return Response.status(400).entity("No file attached").build();

    StringBuilder fileName = new StringBuilder("");
    StringBuilder archiveName = new StringBuilder("");
    StringBuilder buildCommand = new StringBuilder("");

    for(int i = 0; it.hasNext(); i++) {
        DataHandler dataHandler = attachment.getDataHandler();
        MultivaluedMap<String, String> map = attachment.getHeaders();
        String[] contentDisposition = map.getFirst("Content-Disposition").split(";");

        if(i == 0) {
            stream = dataHandler.getInputStream();
            Response saveFileResponse = handleFileStream(contentDisposition, stream, fileName);
            if (saveFileResponse != null)
                return saveFileResponse;
        } else if (i == 1) {
            if (!handleFormParam(contentDisposition, archiveName))
                return Response.status(400).entity("Missing FormParam: archive_name").build();
        }
    .
    .
    .
private boolean handleFormParam(String[] contentDisposition, StringBuilder stringBuilder) {
    String formElementName = null;
    for (String tempName : contentDisposition) {
        String[] names = tempName.split("=");
        for (String n : names) {
            System.out.println(tempName + ":" + n);
        }
    }
    if (stringBuilder.length() == 0) {
        return false;
    }
    return true;
}

The only information about the "archive_name" form param I can get from the attachment is that the name of the param is "archive_name". How do I get the value associated with "archive_name"?

Casey
  • 21
  • 2

1 Answers1

0

I think you're saying you want to submit other text form parameters along with the file to upload, correct? Like:

<form action="upload" method="post" enctype="multipart/form-data">
    Name: <input name="myName" type="text"/><br>
    File: <input name="document" type="file"/><br>
    <input type="submit"/>
</form>

If so, while I've only done this under older JAX-RS, I think the issue is that those extra field values don't arrive inside the Content-Disposition header, but like in the "body" of the "part". The older WebSphere JAX-RS, based on Apache Wink instead of CXF, actually had a part.getBody() method, and this is what worked for us.

If I use browser developer tools to watch the actual POST content of such a form, this is what the extra parameters look like:

-----------------------------18059782765430180341846081335
Content-Disposition: form-data; name="myName"

Joe Smith

So I'd look for other methods on that (apparently IBM-specific) class, IAttachment, or maybe the DataHandler, that might get you text from the body of the part.

dbreaux
  • 4,982
  • 1
  • 25
  • 64
  • I spent some time working on it, but I still can't figure it out. In the meantime, I decided it would be better to change the application to accept Query Parameters instead. Thanks for the help! – Casey Jan 31 '18 at 20:32