Hi Craig,
Wow! I think you nailed it :-) the huge value here is that developers
do not require to understand some of the inner workings of how
multipart/form-data works.
This now makes it possible to for the @FormParam for multipart/form-
data to the jersey mulitpart-module and will make it easier to build
any bean based approach.
Paul.
On Dec 17, 2008, at 1:22 AM, Craig McClanahan wrote:
> Paul Sandoz wrote:
>> Hi Craig,
>>
>> I think your example reflects that we could do more to support
>> multupart/form-data with the multipart module.
>>
> I've just checked in some initial support for more user-friendly
> multipart/form-data handling. As you had suggested, subclasses
> FormDataMultiPart and FormDataBodyPart provide convenient APIs to
> treat the message as a set of named fields, rather than a set of
> independent body parts.
>
> As an example (similar to logic in the unit tests), let's say you
> have a client that wants to send three fields -- two string fields
> and an arbitrary JavaBean for which I have a MessageBodyWriter. The
> client code, using Jersey client, could look something like this:
>
> WebResource service = ...;
>
> String name = "name value";
> String id = "id value";
> MyClass bean = ...;
>
> FormDataMultiPart = new FormDataMultiPart().
> field("name", name).
> field("id", id).
> field("bean", bean, MediaType.TEXT_XML_TYPE);
> ClientResponse = service.path("/path").
> type(MediaType.MULTIPART_FORM_DATA_TYPE).
> post(ClientResponse.class, multiPart);
>
> Handling this at the server end might look something like this:
>
> @POST
> @Consumes("multipart/form-data")
> public Response post(FormDataMultiPart multiPart) {
> String name = multiPart.getField("name").getValue();
> String id = multiPart.getField("id").getValue();
> MyClass bean =
> multiPart.getFIeld("bean").getValueAs(MyClass.class);
> ... do something with this data ...
> return Response.ok().build();
> }
>
> which is a *lot* simpler, on both ends, than the code to use
> multipart/form-data without the specialized helpers.
>
> There is one use case in RFC 2388 (the multipart/form-data) spec
> that I didn't explicitly cover, but I'm not sure it needs anything
> extra. That's when you want to send a single field as a set of
> files, instead of just one. The spec says you should use a nested
> multipart/mixed to contain the set, which you can do with the
> regular jersey-multipart classes pretty easily.
>
Agreed, but perhaps we could make it easier to set the content
disposition with the file parameter. I am not sure how much the form-
based classes should validate the information in the content
disposition and return errors.
> By the way, if a client really *does* want to send the content of a
> file, instead of a serialized bean, just set the field value to an
> InputStream pointing at the content.
You can also use an instance of File :-)
> JAX-RS implementations (including Jersey) are required to support a
> Provider that just copies the bytes from this stream, so yoiu don't
> have to do anything else special. At the server end, you can
> acquire an InputStream reference to the uploaded bytes something
> like this:
>
> InputStream stream = ((BodyPartEntity)
> multiPart.getField("file").getEntitiy()).getInputStream();
>
> and copy the bytes to wherever you want.
>
Yes. It is possible to use File on the server side as well and a
temporary file will be created. But i think we have similar issues
w.r.t. cleaning up files when they are not used.
Paul.