users@jersey.java.net

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

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 16 Dec 2008 11:51:32 +0100

Hi Craig,

I think your example reflects that we could do more to support
multupart/form-data with the multipart module.

For an outbound message we need a way to easily set the content
disposition and its properties, including the name.

For an inbound message we need a way to easily get the body part given
a name that corresponds to the name property a content disposition of
a body part.

Do we need to extend MultPart with FormDataMultPart ? and BodyPart
with FormDataBodyPart ?

Maybe a class that extends MultiPart class for managing a set of
files? as clients can upload a set of files using multipart/mixed?

I am deriving cases from here:

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2

We have a headers for ContentDisposition and
FormDataContentDisposition for parsing but there is no support yet for
writing.

Paul.

On Dec 14, 2008, at 10:28 PM, Craig McClanahan wrote:

> sarat.pediredla wrote:
>> Hi,
>>
>> I have been trawling the mailing list for the past hour trying to
>> find a
>> solution to this and could not, so I gave up and thought I might
>> just ask.
>>
>> I have a REST API, which work's great when serialising from and to
>> JSON/XML.
>> This serves me great but now I want to start accepting attachments
>> (primarily binary images) through the REST API and wanted to see
>> how this
>> could be achieved.
>>
>> Here is a sample requirement,
>>
>> "I want to be able to POST a note, along with an attachment to the
>> API and
>> have it create the Note (which is a JAXB Bean) and save the
>> attachment to
>> file, assigning the disk file path to Note.setAttachmentPath(String
>> filePath))"
>>
>> The problem is being able to POST both the Note object and binary
>> attachment
>> in 1 request, so I figured the only easy way for me to get this to
>> work is
>> use @Consumes("multipart/form-data").
>> I hear I could use jersey-multipart to handle this, but I can find no
>> documentation on how this will work. Ideally, I would like
>> something like
>> this,
>>
>> @POST
>> @Consumes("multipart/form-data")
>> public String postNote(
>> Note note,
>> File file) throws Exception {
>> ..
>> }
>> I saw another note from Paul Sandoz somewhere which mentions the
>> use of
>> FormDataContentDisposition like below,
>>
>> @POST
>> @Consumes("multipart/form-data")
>> public String post(
>> @FormParam("file") JAXBBean f,
>> @FormParam("file") FormDataContentDisposition fdc)
>> throws Exception {
>> ..
>> }
>> However, this doesn't really explain how to use the jersey-
>> multipart request
>> to read the file and save it (I would prefer to use Apache Commons
>> to save
>> the file to disk, like I do in my struts2 actions)
>>
>> Any help?
>>
> Jersey-multipart was indeed designed for things like this, but
> doesn't include the "copy a file" part directly, although that is
> pretty easy to implement. Let's presume that your client sends a
> "multipart/mixed" message, rather than "multipart/form-data" -- I'll
> show some sample client code for that further down -- where the
> first part is your Note object (serialized with JAXB), and the
> second part is the binary attachment. On the second part, the
> client can send whatever media type it wants, but we're going to
> assume it's a binary data stream and not try to parse it -- we just
> want to store it.
>
> The server side might look something like this:
>
> @POST
> @Consumes("multipart/mixed")
> public Response post(MultiPart multiPart) {
> // First part contains a Note object serialized by JAXB, so
> pull it back out
> Note note =
> multiPart.getBodyParts().get(0).getEntityAs(Note.class);
> // We do not know what type the second part is, so get an
> input stream
> // to the content so we can save it to disk
> BodyPartEntity bpe = (BodyPartEntity)
> multiPart.getBodyParts().get(1).getEntity();
> InputStream stream = bpe.getInputStream();
> // Now we can copy the bytes from this body part entity to
> wherever we want
> ...
> }
>
> If your client uses Jersey, you can also use jersey-multipart to
> construct the request to be sent, using code something like this:
>
> WebResource service = ...; // Create a WebResource instance
> pointing at your web service
>
> Note note = ...; // Note object for the first body part
> byte[] data = ...; // Byte array containing the data for the
> attachment
> // Construct a MultiPart containing the two body parts with our data
> MultiPart multiPart = new MultiPart().
> bodyPart(new BodyPart(note, MediaType.APPLICATION_XML_TYPE)).
> bodyPart(new BodyPart(data,
> MediaType.APPLICATION_OCTET_STREAM_TYPE));
> // Use a POST to send this as a single request
> ClientResponse response =
> service.path("/myservice").type("multipart/
> mixed").post(ClientResponse.class, multiPart);
> ...
>
> It's a little more complicated if the client side data is really a
> disk file and is potentially too big to fit in memory. In that
> case, you'll need to provide some sort of Java class for the second
> body part's entity (perhaps configured with the file path), along
> with a JAX-RS MessageBodyWriter that knows how stream the bytes from
> the file out to the output stream. Providing such gadgets would
> make a nice enhancement to jersey-client (they would be useful
> outside the context of just jersey-multipart) ... I will do some
> thinking of what general support for this might look like.
>
> Hope this helps.
>
> Craig
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>