Paul Sandoz wrote:
> Hi Craig,
>
> I think your example reflects that we could do more to support
> multupart/form-data with the multipart module.
Agreed. This media type wasn't my initial priority, but we should
definitely make sure it is supported elegantly.
>
> For an outbound message we need a way to easily set the content
> disposition and its properties, including the name.
>
There is a way to do this today, but doesn't really count as elegant:
BodyPart bp = ...;
bp.getHeaders().putSingle("Content-Disposition", "form-data; name="
+ filename);
A BodyPart subclass that set this header automatically, and offered a
property to set the filename, would be straightforward.
> 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.
>
Again, you can do it with the existing code today, but you have to scan
all the body parts, and use getParameterizedHeaders(), to look for
fields by name.
> Do we need to extend MultPart with FormDataMultPart ? and BodyPart
> with FormDataBodyPart ?
>
I think this would definitely help. I've got a bit of time this week
where I can take a deeper look.
> Maybe a class that extends MultiPart class for managing a set of
> files? as clients can upload a set of files using multipart/mixed?
>
What particular use cases are you thinking about here? I'll be looking
at the HTML spec section you quote below, but it would be helpful to get
a general idea of what you'd like.
> 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.
That would appear to be the case for all of the header classes, not just
these two. Does it make sense to consider dealing with all of them?
>
> Paul.
Craig
>
> 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
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>