I'm using jersey and spring in my application. I don't have any issue when working with any AJAX requests but i get media not supported error when uploading files. I tried several ways, but haven't find any fix for it. Wondering if anyone can help me find the root cause of the issue. Appreciate your help.
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.blanc.whiteboard.RestResourceApplication</param-value>
</init-param>
<init-param>
<param-name>org.glassfish.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
@Path("/upload")
@POST
//@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadAsset(@Context SecurityContext sc,
MultipartHttpServletRequest request) {
User user = loadUserFromSecurityContext(sc);
MultipartFile file = null;
// 1. build an iterator
Iterator<String> itr = request.getFileNames();
// 2. get each file
while (itr.hasNext()) {
// 2.1 get next MultipartFile
file = request.getFile(itr.next());
if (file == null) {
throw new FileUploadException("File is null.");
}
LOG.info(file.getOriginalFilename() + " uploaded! " + files.size());
// 2.2 if files > 10 remove the first from list
if (files.size() > 10)
files.pop();
}
return Response.ok().build();
}
<jersey.version>2.20</jersey.version>
.....
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-aop</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-beans</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-web</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- File upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
Aug 12, 2015 7:21:58 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 4 * Server responded with a response on thread http-bio-8080-exec-5
4 < 200
4 < Access-Control-Allow-Headers: X-HTTP-Method-Override, Content-Type, x-requested-with, Authorization, Cache-Control
4 < Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4 < Access-Control-Allow-Origin: http://localhost:9000
4 < Access-Control-Max-Age: 3600
4 < Content-Type: application/json
Aug 12, 2015 7:22:15 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 5 * Server has received a request on thread http-bio-8080-exec-1
5 > OPTIONS http://localhost:8080/v1.0/assets/upload
5 > accept: */*
5 > accept-encoding: gzip, deflate, sdch
5 > accept-language: en-US,en;q=0.8
5 > access-control-request-headers: accept, cache-control, content-type, x-requested-with
5 > access-control-request-method: POST
5 > cache-control: no-cache
5 > connection: keep-alive
5 > host: localhost:8080
5 > origin: http://localhost:9000
5 > pragma: no-cache
5 > referer: http://localhost:9000/debug.html
5 > user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36
Aug 12, 2015 7:22:15 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 5 * Server responded with a response on thread http-bio-8080-exec-1
5 < 200
5 < Access-Control-Allow-Headers: X-HTTP-Method-Override, Content-Type, x-requested-with, Authorization, Cache-Control
5 < Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
5 < Access-Control-Allow-Origin: http://localhost:9000
5 < Access-Control-Max-Age: 3600
5 < Allow: POST,OPTIONS
5 < Content-Type: application/vnd.sun.wadl+xml
5 < Last-modified: Wed, 12 Aug 2015 19:22:15 EDT
Aug 12, 2015 7:22:15 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 6 * Server has received a request on thread http-bio-8080-exec-10
6 > POST http://localhost:8080/v1.0/assets/upload
6 > accept: application/json
6 > accept-encoding: gzip, deflate
6 > accept-language: en-US,en;q=0.8
6 > cache-control: no-cache
6 > connection: keep-alive
6 > content-length: 108054
6 > content-type: multipart/form-data; boundary=----WebKitFormBoundarywS3v9iwIqD3NwnYt
6 > host: localhost:8080
6 > origin: http://localhost:9000
6 > pragma: no-cache
6 > referer: http://localhost:9000/debug.html
6 > user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36
6 > x-requested-with: XMLHttpRequest
19:22:15.340 [http-bio-8080-exec-10] INFO o.b.w.r.GenericExceptionMapper - Web Application Exception: **javax.ws.rs.NotSupportedException: HTTP 415 Unsupported Media Type**
Aug 12, 2015 7:22:15 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 6 * Server responded with a response on thread http-bio-8080-exec-10
6 < 415
6 < Access-Control-Allow-Headers: X-HTTP-Method-Override, Content-Type, x-requested-with, Authorization, Cache-Control
6 < Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
6 < Access-Control-Allow-Origin: http://localhost:9000
6 < Access-Control-Max-Age: 3600
On front end i'm using [dropzone][1]
You can't just expect the request body to be parsed into arbitrary data types (i.e. MultipartHttpServletRequest
). How it works (with Jersey and JAX-RS) is through MessageBodyReader
s (you can read more here).
Basically, based on the Content-Type
of the request (which is multipart/form-data
), and the method parameter type (MultipartHttpServletRequest
), Jersey will look through it's registry for a MessageBodyReader
that can handle those two factors. If it can't find one, it will throw the exception you are facing and send s 415.
That being said, what you should do is just use the multipart support already provided by Jersey. It comes with the needed MessageBodyReader
to handle some Jersey specific (and other common) data types for multipart data. You first need the dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
Then you need to register the feature, which you've already done by adding the feature classname in your init-param
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.filter.LoggingFilter;
org.glassfish.jersey.media.multipart.MultiPartFeature
</param-value>
</init-param>
Then you just need to use it's components. The link I provided is give a full explanation. The most common way to use this feature is to use the @FormDataParam
annotation for your method parameters. For example
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadAsset(@FormDataParam("file") InputStream in) {}
where the InputStream
is a particular file with the name "file"
in the Content-Disposition.
There are a few other ways to accept files. You can include the entire multipart body, and just iterate through the parts, like you are currently doing. For example
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadAsset(FormDataMultiPart multipart) {
Map<String, List<FormDataBodyPart>> map = multipart.getFields();
for (Map.Entry<String, List<FormDataBodyPart>> entry: map.entrySet()) {
for (FormDataBodyPart part: entry.getValue()) {
InputStream in = part.getEntityAs(InputStream.class);
String name = part.getName();
}
}
}
For more information, visit the link I provided above.