2

I'm trying to upload a file using Jersey but I'm facing a lot of trouble. I saw that i have to configure MultiPartFeature to make things happen but I couldn't make it work. I understand that i have to enable multipart feature on jersey but that's the problem.

I tried to configure a custom Application and ResourceConfig but for some reason when I do this my rest services stop working. I also tried to add an <init-param> enabling MultiPart but didn't work as well.

I'm using Tomcat7, Spring, Jersey with Jackson

These are couple of the approaches I tried.

org.glassfish.jersey upload file with FormDataContentDisposition

Uploading file using Jersey over RESTfull service and The resource configuration is not modifiable?

I'm using the default servlet configuration javax.ws.rs.core.Application to map my rest services. And I guess this is the whole problem but as I mentioned before when I tried to map a custom Application ou ResourceConfig I get other problems

This is my current configuration. With this configuration everything works great except the Multipart

web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

<error-page>
    <error-code>404</error-code>
    <location>/not-found.html</location>
</error-page>

<context-param>
    <param-name>STORAGE_PROPERTY</param-name>
    <param-value>${user.home}/tec-imovel/STORAGE/property</param-value>
</context-param>

<context-param>
    <param-name>STORAGE_USER</param-name>
    <param-value>${user.home}/tec-imovel/STORAGE/user</param-value>
</context-param>


<filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
        <param-name>ExpiresByType image</param-name>
        <param-value>A2592000 </param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType text/css</param-name>
        <param-value>A2592000</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType application/javascript</param-name>
        <param-value>A2592000</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!-- Spring Security Char Encoding Filter-->
<filter>
    <filter-name>encoding-filter</filter-name>
    <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>encoding-filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


<!-- Servlet declaration can be omitted in which case it would be automatically
    added by Jersey-->
<servlet>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>


<!-- Upload de imagens de usuario -->
<servlet>
    <servlet-name>ImagemUsuarioUploadServlet</servlet-name>
    <servlet-class>com.tecimovel.upload.servlet.ImagemUsuarioUploadServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>ImagemUsuarioUploadServlet</servlet-name>
    <url-pattern>/imagem-usuario-upload</url-pattern>
</servlet-mapping>

<!-- Upload de imagens de imovel -->
<servlet>
    <servlet-name>ImagemImovelUploadServlet</servlet-name>
    <servlet-class>com.tecimovel.upload.servlet.ImagemImovelUploadServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>ImagemImovelUploadServlet</servlet-name>
    <url-pattern>/imagem-imovel-upload</url-pattern>
</servlet-mapping>

<!-- Servlet de download de imagens do imovel -->
<servlet>
    <servlet-name>DownloadImagemImovelServlet</servlet-name>
    <servlet-class>com.tecimovel.download.servlet.DownloadImagemImovelServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>DownloadImagemImovelServlet</servlet-name>
    <url-pattern>/download-imagem-imovel/*</url-pattern>
</servlet-mapping>

<!-- Servlet de download de imagens do usuario -->
<servlet>
    <servlet-name>DownloadImagemUsuarioServlet</servlet-name>
    <servlet-class>com.tecimovel.download.servlet.DownloadImagemUsuarioServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>DownloadImagemUsuarioServlet</servlet-name>
    <url-pattern>/download-imagem-usuario/*</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml,/WEB-INF/spring-security.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/classes/log4j.web.properties</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

<!-- Open Session View -->
<filter>
    <filter-name>oemInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactory</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>oemInViewFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
</filter-mapping>

<resource-ref>
    <description>PostgreSQL DataSource</description>
    <res-ref-name>jdbc/TECIMOVELDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

<filter>
    <filter-name>crawlerFilter</filter-name>
    <filter-class>com.tecimovel.filter.CrawlerFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>crawlerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>WebResourceOptimizer</filter-name>
    <filter-class>ro.isdc.wro.http.WroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>WebResourceOptimizer</filter-name>
    <url-pattern>/wro/*</url-pattern>
</filter-mapping>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>tec-imovel</groupId>
<artifactId>tec-imovel</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>tec-imovel</name>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<repositories>
    <repository>
        <id>apache.snapshots</id>
        <url>http://repository.apache.org/snapshots/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.7</version>
    </dependency>

    <dependency>
        <groupId>net.coobird</groupId>
        <artifactId>thumbnailator</artifactId>
        <version>0.4.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-imaging</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-http</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-bean-validation</artifactId>
        <version>2.9</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.7</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.6</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>2.6</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.12.6</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.1-901.jdbc4</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring3</artifactId>
        <version>2.8</version>
    </dependency>
    <dependency>
        <groupId>commons-pool</groupId>
        <artifactId>commons-pool</artifactId>
        <version>1.4</version>
        <!-- <version>1.5.6</version> -->
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <!-- <dependency> -->
    <!-- <groupId>org.springframework</groupId> -->
    <!-- <artifactId>spring-context</artifactId> -->
    <!-- <version>4.0.4.RELEASE</version> -->
    <!-- </dependency> -->

    <!-- <dependency> -->
    <!-- <groupId>org.springframework</groupId> -->
    <!-- <artifactId>spring-core</artifactId> -->
    <!-- <version>4.0.3.RELEASE</version> -->
    <!-- </dependency> -->

    <!--LOGGING SPRING -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-email</artifactId>
        <version>1.3.2</version>
    </dependency>

    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.9.2</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk</artifactId>
        <version>1.7.13</version>
    </dependency>


    <dependency>
        <groupId>ro.isdc.wro4j</groupId>
        <artifactId>wro4j-core</artifactId>
        <version>1.7.6</version>
    </dependency>


    <!-- Hibernate EHCache API -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
     <!-- EHCache uses slf4j for logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.5</version>
    </dependency>


    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>14.0.1</version>
    </dependency>

</dependencies>

<build>
    <finalName>tec-imovel</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <inherited>true</inherited>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <path>/</path>
            </configuration>
        </plugin>

        <!-- <plugin> -->
        <!-- <groupId>org.zeroturnaround</groupId> -->
        <!-- <artifactId>jrebel-maven-plugin</artifactId> -->
        <!-- <version>1.1.5</version> -->
        <!-- <configuration> -->
        <!-- <addResourcesDirToRebelXml>true</addResourcesDirToRebelXml> -->
        <!-- <alwaysGenerate>true</alwaysGenerate> -->
        <!-- </configuration> -->
        <!-- <executions> -->
        <!-- <execution> -->
        <!-- <id>generate-rebel-xml</id> -->
        <!-- <phase>process-resources</phase> -->
        <!-- <goals> -->
        <!-- <goal>generate</goal> -->
        <!-- </goals> -->
        <!-- </execution> -->
        <!-- </executions> -->
        <!-- </plugin> -->


    </plugins>
</build>

<properties>
    <jersey.version>2.6</jersey.version>
    <hibernate.version>4.3.5.Final</hibernate.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Service that receives uploaded file

@Path("/migracao")
public class MigracaoRS {

    @Autowired
    private MigracaoGenericService migracaoGenericService;

    @Autowired
    private UsuarioController usuarioController;

    //IF I DON'T COMMENT THIS METHOD THE SERVER DOESN'T EVEN START BECAUSE OF THE MULTIPART THING
    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public void uploadFile(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) {
        migracaoGenericService.migrar(uploadedInputStream, usuarioController.getUsuarioLogado());
    }
}

Init param in jersey servlet. If I add this init-param my rest services stop working :(

    <servlet>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>
Community
  • 1
  • 1
Viny Machado
  • 582
  • 12
  • 23
  • You tried to add the classnames init-param inside the javax.ws.rs.Application servlet definition? Also what result are you getting that says its not working? – Paul Samsotha May 17 '15 at 05:40
  • Sorry I didn't read the comment in the code. But when I set the init-param in the servlet definition, it works fine. Without it, I get the same result you're facing. Can you show exactly how you used the init-param. Maybe you put it in the wrong place. – Paul Samsotha May 17 '15 at 05:55
  • Another thing, you already have a `` property in your pom. You should use it in your `` definitions. I see you're mixing versions. You should use `${jersey.version}` instead of the static version to keep them consistent. Actually you don't even need the version. That's what the `bom` is for. You could completely get rid of the version in the jersey dependency definitions, and it will all be the same – Paul Samsotha May 17 '15 at 05:59
  • @peeskillet Thanks for you help. I put how I set the init-param in the last part of the question. If I set the init-param my rest services stop working :( – Viny Machado May 17 '15 at 20:12
  • @peeskillet When I said my rest services stop working I mean they all return 404 – Viny Machado May 17 '15 at 20:18

2 Answers2

1

Yeah so the original servlet configuration you had

<servlet>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <load-on-startup>1</load-on-startup>
</servlet>

allows for registration of classes through classpath scanning. Once you add the <init-param> ...provider.classnames, you are saying to Jersey, "don't register all those resources and providers you found on the classpath, I will register them myself".

So to fix that, you can add the <init-param> to scan your project packages, or any other packages on the classpath (like other jars).

<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>
        the.packages.to.scan,
        multiple.pacakges,
        can.be.separated.by.comma
    </param-value>
</init-param>

It's not the same as scanning the classpath, but for the most part, all your resources should be in your project anyway, and if not, just register the jar package explicitly.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I try add the package scan as you said but I got another error. It seams the Entity to Json conversion is not working after I add this init-param. In this [link](http://pastebin.com/d1Vt5EmG) you can see how I configure the Jersey servlet and the exception message – Viny Machado May 18 '15 at 02:18
  • You can register the JacksonFeature either by class (to the ...classnames init-param) `org.glassfish.jersey.jackson.JacksonFeature` (comma separated) or register the package `com.fasterxml.jackson.jaxrs.json` (in the packages init-param) – Paul Samsotha May 18 '15 at 02:20
  • After I also added this package to scan "org.codehaus.jackson.jaxrs" my rest services are working again. Now i'm gonna try to make the upload file works. Thanks a lot for your help! – Viny Machado May 18 '15 at 02:29
0

I think it will be easier for you to use JSON as consumer and pass your file as byte array this will make it part of you json request.

Alaa Abuzaghleh
  • 1,023
  • 6
  • 11