1

I am trying to build a rest service to upload a file. Here is what I've got. When I test in postman, I have form-data selected with "file" set to the file that I'm uploading.

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(@RequestParam("file") MultipartFile file)

My understanding is that I need the jersey-media-multipart dependency

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

When I try to make the post request, I get a 415 Unsupported Media Type error, and I am not sure why. It is set to consume MULTIPART_FORM_DATA and the parameter is a MultipartFile.

EDIT I've added a configuration as follows,

@Configuration
public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(MultiPartFeature.class);
    }
}

I've also fixed my resource

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

And now I get [[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response

Here is my spring boot class, which contains additional configuration

    @SpringBootApplication
@EnableCircuitBreaker
@EntityScan("com.whatever.")
@ImportResource({"classpath*:/META-INF/**/spring-bootstrap.xml"})
@Import({JerseyConfig.class})
@EnableJpaRepositories(basePackages="whatever", entityManagerFactoryRef="entityManagerFactory")
public class Application {

protected TomcatEmbeddedServletContainerFactory createTomcatEmbeddedServletContainerFactory() {
        return new TomcatEmbeddedServletContainerFactory() {

            @Override
            protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
                ((StandardHost) tomcat.getHost()).setErrorReportValveClass(StringUtils.EMPTY);
                return super.getTomcatEmbeddedServletContainer(tomcat);
            }
        };
    }

    @Bean
    public FilterRegistrationBean requestContextFilter() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new org.springframework.web.filter.RequestContextFilter());
        filterRegistration.setName("RequestContextFilter");
        filterRegistration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
        filterRegistration.addUrlPatterns(BASE_PATH + "*");
        return filterRegistration;
    }    

    @Bean 
    public FilterRegistrationBean springSecurityFilterChain() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new org.springframework.web.filter.DelegatingFilterProxy());
        filterRegistration.setName("SpringSecurityFilterChain");
        filterRegistration.setOrder(Ordered.HIGHEST_PRECEDENCE + 2);
        filterRegistration.addUrlPatterns(BASE_PATH + "*");
        return filterRegistration;
    }

    @Bean
    @Conditional(NonWindowsCondition.class)
    public FilterRegistrationBean f5Filter() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new F5Filter());
        filterRegistration.setName("F5Filter");
        filterRegistration.setOrder(Ordered.HIGHEST_PRECEDENCE + 3);
        filterRegistration.addUrlPatterns(BASE_PATH + "*");
        return filterRegistration;
    }  

    /**
     * Initializes and registers the JAX-RS filter implementation, currently Jersey.
     * 
     * @return The JAX-RS filter registration.
     * @throws ClassNotFoundException 
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     */
    @Bean
    public FilterRegistrationBean jaxrsFilter() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Filter filter = (Filter) Class.forName("org.glassfish.jersey.servlet.ServletContainer").newInstance();
        jerseyFilterRegistration.setFilter(filter);
        jerseyFilterRegistration.setName("JerseyFilter");
        jerseyFilterRegistration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
        // Set the Jersey filter mapping and context path
        jerseyFilterRegistration.addUrlPatterns(BASE_PATH + "*");
        jerseyFilterRegistration.addInitParameter("jersey.config.servlet.filter.contextPath", BASE_PATH);
        // Load the common package and application package
        jerseyFilterRegistration.addInitParameter("jersey.config.server.provider.packages", "com.whatever.jaxrs.feature;com.whatever.fig.risk.webservice.resource");
        // Enable media type mappings on the URI such as .xml and .json
        jerseyFilterRegistration.addInitParameter("jersey.config.server.mediaTypeMappings", "xml:application/xml, json:application/json");
        // Enable Java bean validation integration
        jerseyFilterRegistration.addInitParameter("jersey.config.beanValidation.enableOutputValidationErrorEntity.servers", "true");
        // Disable the application.wadl from being generated and publicly visible (ITSO finding)
        jerseyFilterRegistration.addInitParameter("jersey.config.server.wadl.disableWadl", "true");        
        // Forward 404s to Spring MVC, which serves up the Actuator endpoints and non-jersey resources 
        jerseyFilterRegistration.addInitParameter("jersey.config.servlet.filter.forwardOn404", "true");

        if (isJerseyDebug) {
            // Debug parameter switches
            jerseyFilterRegistration.addInitParameter("jersey.config.server.monitoring.statistics.enabled", "true");
            jerseyFilterRegistration.addInitParameter("jersey.config.server.tracing.type", "ALL");
            jerseyFilterRegistration.addInitParameter("jersey.config.server.tracing.threshold", "VERBOSE");
        }

        return jerseyFilterRegistration;
    }
Steve
  • 4,457
  • 12
  • 48
  • 89
  • Your `JerseyConfig` is not the configuration class being used. If it was, you would not get this error. How are you configuring your application? Is it with a web.xml? Are you using Spring boot? – Paul Samsotha May 18 '18 at 20:53
  • I'm using Spring boot. So my main class needs to extend ResourceConfig I'm guessing – Steve May 21 '18 at 14:30
  • Is that `JerseyConfig` class where you are configuring the rest of the Jersey application? – Paul Samsotha May 21 '18 at 14:52
  • I've copied down some configuration stuff from my main spring boot class. This is all I have. I didn't think it was applicable to our current situation, but I may be wrong. All I have in the jersey config is the line that you suggested that I add. – Steve May 21 '18 at 15:15
  • Not sure why you are configuring Jersey this way, i.e with a `FilterRegistrationBean`. If you are going to do it this way, then you need to look at the `init-param` configuration for the MultiPartFeature from the link in my answer. – Paul Samsotha May 21 '18 at 15:39

1 Answers1

1

@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:

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720