File Upload Along with Other Object in Jersey Restful Web Service

Jersey restful web service - File upload with multiple object

  1. You're using the wrong version multipart dependency. Anytime you see com.sun.jersey in the package, that is for Jersey 1.x, and you should not use it for a 2.x project. You will need to switch versions and then register the MultiPartFeature. For more information, see MULTIPART_FORM_DATA: No injection source found for a parameter of type public javax.ws.rs.core.Response

  2. Unless the client is able to set the Content-Type for each body part (some clients can't), you will need to tweak the method a little bit, in order to get the result an object. For example

    public Response post(@FormDataParam("doc") FormDataBodyPart docpart) {
    docpart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
    UserDocument doc = docpart.getValueAs(UserDocument.class);
    }

    For the InputStream parameter, you don't need to do this. For more detail, see File upload along with other object in Jersey restful web service

Multiple files upload in a REST service using Jersey

The problem is with the method parameter (the presence of the @FormDataParam)

public Response bulkUpload(@FormDataParam("file") FormDataMultiPart multiPart) {}

@FormDataParam is used when you want to declaratively extract individual parts from the multipart request, whereas FormDataMultiPart is used to get an entire multipart body and programmatically extract each part. It's possible to have a nested multipart where a complete multipart is an individual part (in which case what you have would work), but this is not the case here.

If you remove the @FormDataParam("file"), then it will work as expected. You can start extracting parts out of the multipart using the method you are using getField(fieldName). This will give you a FormDataBodyPart for each part you extract. You can get the data with FormDataBodyPart#getValueAs(InputStream.class) if you want that part as an InputStream, or you can use File.class or byte[].class, whatever your preference. This is how to extract data from the FormDataMultiPart.

Each part has it's own name and you extract the part using that name. In the case of your cURL request, you sent one part, and the part's name is file. i.e. "file=@/Users/...". So if you want to send another part, just add another parameter with a different name1, as mentioned by Vladimir:

curl -X POST "http://localhost:37200/api/sample-bulk"\
-H "accept: application/json"\
-H "Content-Type: multipart/form-data"\
-F "file1=@/Users/naman/Desktop/Media/video.mp4"\
-F "file2=@/Users/naman/Desktop/Media/another_video.mp4"

As I mentioned earlier, @FormDataParam is used to extract parts declaratively. You use the part's name as the annotation value. So with the previous cURL command, you could do.

public Response bulkUpload(
@FormDataParam("file1") InputStream file1,
@FormDaraParam("file1") FormDataContentDisposition file1Fdcd,
@FormDataParam("file2") InputStream file2,
@FormDaraParam("file2") FormDataContentDisposition file2Fdcd) {
}

You can get information about the part, such as the file name from the FormDataContentDisposition.

See also

  • Why “FormDataMultiPart” type parameter is treated differently
  • Jersey documentation for its multipart support (on the server side)
  • File upload along with other object in Jersey restful web service

Footnotes

  1. Parts can have the same name also, e.g.

    -F file=@path_to_file1
    -F file=@path_to_file2

    This is the reason when you try to get a part programmatically, you get a list of FormDataBodyParts instead of a single object i.e

    FormDataMultiPart multiPart = ...
    List<FormDataBodyPart> files = multiPart.getField("file");

    And if you wanted to get them declaratively, you would use a List instead of a single object type

    public Response upload(@FormDataParam("file") List<InputStream> files) { ... }

Java Rest Jersey : Posting multiple types of data (File and JSON)

You should use some multipart format. It basically consists of a single message of type multipart/xxx (where xxx can be something like form-data), and that message consists of other "complete" messages with their own content-type and other meta data.

You haven't specified which Jersey version, but starting with Jersey 2.x.x, there is multipart support available, in the form of a separate artifact:

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>

Then you just need to register the feature, as seen here in Registration.

Then you can just use @FormDataParam

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({MediaType.APPLICATION_JSON})
public CreateTaskVO provideService(
@FormDataParam("meta") String jsonMeta,
@FormDataParam("data") InputStream file,
@FormDataParam("data") FormDataContentDisposition fileDetail) {

You can see here an example of how the data can be sent from the client, and also the internal message body format of a multipart

Other rreading:

  • General Information on Jersey Multipart support
  • General information on multipart/form-data
  • JAX-RS Post multiple objects

UPDATE

There is also support for multipart in Jersey 1.x.x, in the form of this artifact

<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>

415 Unsupported media type on java rest service when uploading file

@RequestParam and MultipartFile are both things that are for Spring not Jersey. For Jersey what you want to use is the annotation @FormDataParam and for the parameter, depending on the part type you can have a number of different type of parameters. If the part is a file, you could use an InputStream, File, or byte[] parameter, or if the part is some plain text, you could have String parameter. If you want the filename, you can add a FormDataContentDisposition parameter alongside the part entity parameters. Below is an example

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(
@FormDataParam("file") InputStream file,
@FormDataParam("file") FormDataContentDisposition fdcd,
@FormDataParam("file-detail") String fileDetail) {

}

To make this work, you need to register the MultiPartFeature with your application. You can see this post for ways you can register it.


See also:

  • File upload along with other object in Jersey restful web service
  • Jersey documentation for Multipart support

How to upload binary file(Photos etc ) with Meta Data using REST

Use multipart/form-data. This is what it's meant for. Not sure which Jersey version you are using, but here is the link for the Jersey 2.x documentation for Multipart support. Here's for 1.x (not really much information). You will need to do some searching for using multipart with Javascript clients (there is a bunch of information out there)

  • Here is a good example of using Jersey 2.x with both the server side and the client API.
  • Here is an example with Jersey 1.x. You can see the API it not much different.


Related Topics



Leave a reply



Submit