Currently, in Wink, multipart/form-data parts will not be passed to a
resource method in the @FormParam annotated method params. In other
words, if you send data from an html form that has declared
enctype="multipart/form-data" (which is what you would use if you wish
to send a file via the file input tag), you have to declare
@Consumes("multipart/form-data") and take as input a
BufferedInMultiPart in your resource method, from which you can
iterate over the InPart(s) and do with the data as you wish.
The bad news is that it means you might have to introduce
Wink-specific objects to your resource class, iterate over the parts,
convert them yourself, etc. This annoys me. :) So I propose we
support the pattern where we go ahead and convert the parts of the
multipart/form-data (or multipart/* -- but I haven't looked into that
yet) into the @FormParam objects requested by the resource method
receiving the inbound request.
The good news is that I've already worked up a patch that supports
something like:
<form enctype="multipart/form-data" action="POST" action="someurl">
<input type="text" name="firstname" />
<input type="file" name="file" /> <!-- browsers will inspect the file
and make a best effort to send appropriate Content-Type header for
this part -->
<input type="submit" /> <!-- browser will not send this data due to
missing the "name" attribute -->
</form>
@POST
@Consumes("multipart/form-data")
public Response postFromForm(@FormParam("firstname") String firstname,
@FormParam("file") File file) {
// good data!
}
The other good news is that when Wink retrieves the parts and attempts
to convert them to the type specified by the @FormParam annotated
method, it will use the existing providers list. So in the above
example, it will simply use the FileProvider. The really good news, I
think, is that this means a application can write a provider that can
convert the inbound file into arbitrary application objects. Let's
say you want a resource method like so:
@POST
@Consumes("multipart/form-data")
public Response postFromForm(@FormParam("file") MyObject myObject) {
// good data, if you have a provider that can do this
}
The client sends a file via a multipart/form-data Content-Type message
in whatever format can be understood by the provider, which could be
(should be?):
@Provider
@Consumes("*/*") // NOT multipart/form-data
class MyProvider implements MessageBodyReader<MyObject> {
public boolean isReadable(...) {
// can do some safety checking here. The MediaType passed in
will be from the Content-Type header on the part, not on the message
// So if the user sent a jpeg from Firefox via a form, you'll
see image/jpeg. It defaults to plain/text. Remember to check that
the genericType
// param is compatible with MyObject!
}
public MyObject readFrom(...) {
// do your magic; marshal the entityStream into MyObject
}
}
I should be able to work up some unittests around this. Anyone see
any issues or problems supporting this?
Besides the above, how about supporting postFiles(@FormParam("file")
List<File> files) ? I don't think this will be difficult to support.
If the resource needed some assurance that the list of files were all
jpeg image files, for example, you could use the provider approach
from above to inspect the content-type header and/or the actual
serialized payload in the message, or the resource method itself would
have to check that. Just a thought. Any thoughts on this?
FYI, the html form for sending such data (two files in two parts of
one message, in this case) looks like this:
<form enctype="multipart/form-data" method="POST" action="someuri">
<input type="file" name="file[]" />
<input type="file" name="file[]" />
<input type="submit" />
</form>
Thanks..
mike