Jersey restful web service - File upload with multiple object
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 theMultiPartFeature
. For more information, see MULTIPART_FORM_DATA: No injection source found for a parameter of type public javax.ws.rs.core.ResponseUnless 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 examplepublic 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
Parts can have the same name also, e.g.
-F file=@path_to_file1
-F file=@path_to_file2This 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 typepublic 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
How to Add Custom Method to Spring Data JPA
How to Use Try-With-Resources with Jdbc
Real World Example of the Strategy Pattern
Preferred Way of Loading Resources in Java
How to Execute In() SQL Queries with Spring's Jdbctemplate Effectively
Float and Double Datatype in Java
How to Sort an Arraylist in Java
Producer/Consumer Threads Using a Queue
Why Does Integer Division Code Give the Wrong Answer
Java String Replace Not Working
Difference Between @Mock and @Injectmocks
How to Print Binary Tree Diagram in Java
What Are All the Different Ways to Create an Object in Java
Implementing Two Interfaces in a Class with Same Method. Which Interface Method Is Overridden
Java Generics with a Class & an Interface - Together
Java.Sql.Sqlexception: - Ora-01000: Maximum Open Cursors Exceeded