users@jersey.java.net

Re: [Jersey] Documentation / Tutorial on using jersey-multipart

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 18 Dec 2008 13:36:19 +0100

On Dec 17, 2008, at 8:33 PM, Craig McClanahan wrote:

> Paul Sandoz wrote:
>> 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.
>>
> Thanks. It sure felt better looking at this sample code, than what
> I had written before :-).
>> 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.
>>
> I can see in the code (MultipartFormDispatchProvider in jersey-
> server) the current support for "multipart/form-data" and
> @FormParam. What I can't see is how I might replace this provider
> with my own so that I can try to create a jersey-multipart based
> version. Any hints?

Currently MultipartFormDispatchProvider is getting an instance of
MimeMultipart and then creating an instance of Map<String,
FormDataBodyPart>, where the key is the name in the content
disposition header. The map instance is added as a property of the
HttpContext. Instead i should be able to add an instance of
FormDataMultiPart as a property and not have to implement the method
getFormData.

There are some complexities about pulling this from the server modile
to the multipart module because the MultipartFormDispatchProvider
extends from FormDispatchProvider. But it should be possible to
duplicate the code.

Paul.

>
>> Paul.
> Craig
>
>>
>> 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.
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>