64

I am using Jersey based restful Service implementation strategy to build a service which will be used to upload files. My service class name is : UploadFileService.java (See Code below)

 package com.jerser.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;

@Path("/fileUpload")
public class UploadFileService {

    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFile(
        @FormDataParam("file") InputStream uploadedInputStream,
        @FormDataParam("file") FormDataContentDisposition fileDetail) {

        String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();

        // save it
        writeToFile(uploadedInputStream, uploadedFileLocation);

        String output = "File uploaded to : " + uploadedFileLocation;

        return Response.status(200).entity(output).build();

    }

    // save uploaded file to new location
    private void writeToFile(InputStream uploadedInputStream,
        String uploadedFileLocation) {

        try {
            OutputStream out = new FileOutputStream(new File(
                    uploadedFileLocation));
            int read = 0;
            byte[] bytes = new byte[1024];

            out = new FileOutputStream(new File(uploadedFileLocation));
            while ((read = uploadedInputStream.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.flush();
            out.close();
        } catch (IOException e) {

            e.printStackTrace();
        }

    }

}

These are the JAR files I have inside my lib:

aopalliance-repackaged-2.4.0-b10.jar     
asm-debug-all-5.0.2.jar     
hk2-api-2.4.0-b10.jar  
hk2-locator-2.4.0-b10.jar     
hk2-utils-2.4.0-b10.jar     
javassist-3.18.1-GA.jar     
javax.annotation-api-1.2.jar     
javax.inject-2.4.0-b10.jar     
javax.servlet-api-3.0.1.jar     
javax.ws.rs-api-2.0.1.jar     
jaxb-api-2.2.7.jar     
jersey-client.jar     
jersey-common.jar     
jersey-container-servlet-core.jar     
jersey-container-servlet.jar     
jersey-core-1.11.jar     
jersey-guava-2.17.jar     
jersey-media-jaxb.jar  
jersey-multipart-1.18.jar    
jersey-server.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar     
persistence-api-1.0.jar    
validation-api-1.1.0.Final.jar

I am getting the following error when I am trying to up my tomcat server :

org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[multipart/form-data], producedTypes=[], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.jerser.service.UploadFileService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@d3e2d4]}, definitionMethod=public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition), parameters=[Parameter [type=class java.io.InputStream, source=file, defaultValue=null], Parameter [type=class com.sun.jersey.core.header.FormDataContentDisposition, source=file, defaultValue=null]], responseType=class javax.ws.rs.core.Response}, nameBindings=[]}']
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:528)
    at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:166)
    at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:327)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:286)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:324)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:338)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:171)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:363)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1176)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1102)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1009)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4885)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5212)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5207)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Over the internet I found there are plenty of example which shows How to upload MULTIPART file using RESTFul API. But with same solution. I am not able to run those code as well. I think I am doing something wrong with the JAR files. Could anyone please help me on this?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Swarup Saha
  • 895
  • 2
  • 11
  • 23

12 Answers12

177

Get rid of jersey-multipart-1.18.jar. That is for Jersey 1.x. Add these two

For Maven you would use the following dependency (you don't need to explicitly add the mimepull dependency, as this one will pull it in).

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>2.17</version> <!-- Make sure the Jersey version matches
                                 the one you are currently using -->
</dependency>

Then you need to register the MultiPartFeature. If you are using a ResourceConfig for configuration, you can simply do

register(MultiPartFeature.class);

If you are using web.xml, then you can add the class as an <init-param> to the Jersey servlet

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>

Note that if you have multiple providers that you want to register, then you can delimit each provider class with a comma, semicolon, or space/newline. You cannot use this same param-name twice. See Suarabh's answer

UPDATE

Also, once you get rid of jersey-multipart-1.18.jar you will have compile errors for the missing imported classes. For the most part, the class names are still the same, just the packages have changed, i.e.


For Dropwizard

If you're using Dropwizard, instead of adding the jersey-media-multipart, they document for your to add dropwizard-forms instead. And instead of registering the MultiPartFeature, you should register the MultiPartBundle

@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
    bootstrap.addBundle(new MultiPartBundle());
}

Really doesn't make much difference though as all the Dropwizard bundle does is register the MultiPartFeature with the ResourceConfig.


Aside

If you are here for a different ModelValidationException, here are some links for information on other causes of the exception.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • 3
    For dropwizard users. One has to include dropwizard-forms dependency, and the register the bundle in the initialize() method: http://dropwizard.readthedocs.io/en/latest/manual/forms.html – Vyacheslav Jul 17 '17 at 09:43
  • Thank you so much, and this is a alternative registery HashSet h = new HashSet>(); h.add(MultiPartFeature.class); – mesutpiskin Aug 07 '17 at 11:49
  • @mesutpiskin Yes, if you are using an `Application` subclass, you would add the `MultiPartFeature` either as a class to the set of classes or as an instance to the list of singletons. – Paul Samsotha Sep 11 '18 at 18:38
  • I ran into this too and just wanted to note that the GlassFish 5.0.1 project (pre-release) at the time of this writing includes Jersey 2.26. – AlanObject Jan 06 '19 at 16:38
  • 1
    Is this answer still valid? I have the same issue, but the `init-param` block in `web.xml` did not fix the issue for me. It only works with the `ResourceConfig`. I would prefer using `web.xml`, though. With `jersey-media-multipart` added, I can use `MediaType.MULTIPART_FORM_DATA` and `@FormDataParam` in my code, however, the validation of the application resource model still fails. I am sure that my `web.xml` is fine, as I also use it for my security-constraints and -roles. Also, what is the mimepull dependency needed for? It does not seem to make a difference if I include it or not. – stefanS Jan 28 '20 at 11:01
  • @stefanS yes the init-param is still valid. – Paul Samsotha Jan 28 '20 at 11:06
  • @PaulSamsotha Could you tell me what the mimepull dependency is needed for? – stefanS Feb 04 '20 at 10:46
  • @stefanS It is used by the jersey-media-mulitpart dependency. That's why it pulls it in as a transitive dependency. The exact use, I am not sure, but I think it has to do with parsing the actual multipart request. – Paul Samsotha Feb 04 '20 at 16:46
9

Yet another possible cause for this very generic error is that Jersey only searches for factories associated with the last annotation when multiple ones are declared on a param. (See bug report)

Until this is fixed, if you are using any other annotations besides @FormDataParam, it has to come last.

This works:

@NotEmpty @FormDataParam("myParam") String myParam

This does not:

@FormDataParam("myParam") @NotEmpty String myParam
Ahmad Abdelghany
  • 11,983
  • 5
  • 41
  • 36
5

I too got the same exception.I did the following changes in web.xml

<init-param>
            <param-name>jersey.config.server.provider.classnames</param-name>
            <param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.moxy.json.MoxyFeature;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
        </init-param>

and changed jersey 2.7 to 2.9 .I do not know what change of this 2 has solved the issue.

Saurabh
  • 7,525
  • 4
  • 45
  • 46
2

If someone is using @FormDataParam with @ApiOperation swagger annotation, it won't work(as per swagger latest version at this time) as mentioned here:

https://github.com/swagger-api/swagger-ui/issues/169

2

Register MultiPartFeature. In web.xml add to the Jersey servlet:

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
RoutesMaps.com
  • 1,628
  • 1
  • 14
  • 19
2

Below code worked for me:

Class ->>> add it

Class Property --->> add it


Public Class userREST () {

@POST
    @Path("upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response uploadImageFile(@FormDataParam("uploadFile") InputStream fileInputStream,
            @FormDataParam("uploadFile") FormDataContentDisposition fileFormDataContentDisposition,
            @FormDataParam("FIR_REG_NUM") String FIR_REG_NUM, @FormDataParam("LOGIN_ID") String LOGIN_ID) {

        final_json_result = WriteFileInFolder.fileAnalysis(fileInputStream, fileFormDataContentDisposition, FIR_REG_NUM,
                LOGIN_ID);

        return Response.ok(final_json_result).build();

    }// uploadImageFile

Public Class FileJAXRSConfig () {

package ####.jaxrs.jwt;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import ####.helper.Common@@@;
import ####.jaxrs.jwt.filters.JWTRequestFilter;
import ####.jaxrs.jwt.filters.JWTResponseFilter;
import ####.service.FileServicesREST;



@ApplicationPath("fileservice")
public class FileJAXRSConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {

        Common@@@.logging("@ApplicationPath@FileServicesREST...");
        Set<Class<?>> clazzes = new HashSet<Class<?>>();
        clazzes.add(JWTRequestFilter.class);
        clazzes.add(FileServicesREST.class);
        clazzes.add(JWTResponseFilter.class);

        return clazzes;
    }


    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("jersey.config.server.provider.packages", "####.service");
        properties.put("jersey.config.server.provider.classnames", "org.glassfish.jersey.media.multipart.MultiPartFeature");
        return properties;
    }

}

Don't need to add following in web.xml

<init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>mha.@@@.service</param-value>
        </init-param>
        <init-param>
            <param-name>jersey.config.server.provider.classnames</param-name>
            <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
        </init-param>
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
1

I had this same problem with Scala and this helped me solve it. Just want to add some Scala specific details to help anyone using Dropwizard with Scala. Here is an example of how to "register" the MultiPartFeature in a Scala and Dropwizard project.

package org.research.s3.service

import io.dropwizard.Application
import io.dropwizard.setup.Environment
import org.research.s3.service.resource._
import org.research.service.s3.resource.UploadResource

import org.glassfish.jersey.media.multipart.{FormDataParam,MultiPartFeature}


class CmdaaApp() extends Application[CmdaaAppConfig] {



  override def run(t: CmdaaAppConfig, env: Environment): Unit = {   

    env.jersey().register(new RootResource)

    //Need this to make the file upload code work in
    env.jersey().register(new MultiPartFeature)
    env.jersey().register(new UploadResource(curBucket))


  }


}

object CmdaaApp {
  def main(args: Array[String]): Unit = new CmdaaApp().run(args: _*)
}

and here is the code for the UploadResource that does the upload:

package org.research.service.s3.resource

import java.io.{FileInputStream, InputStream}


import com.google.gson.{Gson, GsonBuilder}

import javax.ws.rs.core.MediaType.APPLICATION_JSON
import javax.ws.rs._
import javax.ws.rs.core.Response
import javax.ws.rs.core.MediaType
import org.research.util.OptionSerializer
import org.research.s3.service.resource.s3Bucket
import org.glassfish.jersey.media.multipart.{FormDataParam,MultiPartFeature}





@Path("/file")
class UploadResource(currentBucket: s3Bucket) {
  val gsonb = new GsonBuilder()
  gsonb.registerTypeAdapter(classOf[Option[Any]], new OptionSerializer)
  val gson = gsonb.create


  @POST
  @Path("upload")
  @Produces(Array(APPLICATION_JSON))
  @Consumes(Array(MediaType.MULTIPART_FORM_DATA))
 // def uploadFile(): Response = {
  def uploadFile(@FormDataParam("file")  uploadedInputStream: InputStream): Response = {

    /* Need code here to get a uuid for the file name
       Then return the uuid if we have success and of course 200
     */

       Response.ok.entity(currentBucket.upload("testName",uploadedInputStream,false)).build()
    //Response.ok().build()
  }

}

This code refers to an s3 bucket but you don't need that. You can just replace that call with code do download your incoming file data to a regular file.

markgp
  • 11
  • 2
1

I had the same problem when I tried to upload the file. I spent a lot of time until I found a solution to the problem.

1.If you changed version of your JARs files you may have a version conflicts!

Clean up your artifacts/libs and rebuild project.

2.You need to register your UploadFileService class too:

register(MultiPartFeature.class);
register(UploadFileService.class);

Hope it will help someone and save your time.

Olexander Yushko
  • 2,434
  • 16
  • 16
1

in case you are getting this error while writing Dropwizard tests for the upload Resource this is the solution:

  1. add dependency on dropwizard-forms

2.add this in the application file:

    @Override
    public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
        bootstrap.addBundle(new MultiPartBundle());
    }
  1. in the test file add:
    ResourceExtension.builder()
                .addResource(new FileResource())
                .addProvider(new MultiPartFeature())
                .build();
0

In case someone comes across this in the future and is running into the same problem I was running into. Make sure that the annotations you are importing are from the correct packages. In my case I was importing javax.websocket.server.PathParam instead of javax.ws.rs.PathParam.

gline9
  • 73
  • 6
0

I had a very similar problem and the answer that helped me was this https://stackoverflow.com/a/30407999/6801721

I was trying to use a user defined object as a query parameter and from the answer that's usually not allowed unless it meets some conditions.

Barath Sankar
  • 383
  • 4
  • 15
0

Indeed my web.xml was lacking "org.glassfish.jersey.media.multipart.MultiPartFeature" (among other classes) within "jersey.config.server.provider.classnames" parameter value. At least :

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>