1
votes

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;
    }
1
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
I'm using Spring boot. So my main class needs to extend ResourceConfig I'm guessingSteve
Is that JerseyConfig class where you are configuring the rest of the Jersey application?Paul Samsotha
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
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

1 Answers

1
votes

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