0

I am implementing a REST API in a Glassfish servlet with Jersey (2.22.2) and OpenAPI (1.1.2). I would like to allow for sending an Excel file as multipart form data to the following endpoint using the @FormDataParam annotation:

@PUT
@Path("/upload")
@Parameter(description = "Import XML file", required = true, name = "file")
@Parameter(required = true, name = "isABC")
@Parameter(required = true, name = "type")
@Parameter(required = true, name = "year")
@Operation(description = "Imports an Excel file")
@APIResponse(responseCode = "200", description = "Success")
@APIResponse(responseCode = "401", description = "Authentication failed")
@APIResponse(responseCode = "500", description = "Unexpected exception")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@RolesAllowed(UserRoles.ADMIN)
public Response importExcel(@FormDataParam("file") File file, @FormDataParam("isABC") boolean isABC, @FormDataParam("type") String type, @FormDataParam("year") int year) throws MyException {
    importHandler.import(file, isABC, type, year);
    return Response.status(Response.Status.OK).build();
}

When I run the Glassfish servlet I get the following exceptions:

WARNING: No injection source found for a parameter of type public javax.ws.rs.core.Response com.mypackage.importExcel(java.io.File,boolean,java.lang.String,int) throws com.mypackage.MyException at index 0.

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.mypackage.MyResource.importExcel

Configure MultipartFeature with web.xml

According to this Stackoverflow thread I need to use the jersey-media-multipart dependency rather than jersey-multipart and make sure I am using the same version as the Jersey core dependency (2.22.2). I also need to register the MultiPartFeature, which I did in my web.xml as follows:

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

After these changes I still got the same error.


Configure MultipartFeature with ResourceConfig

I tried registering the MultipartFeature in a ResourceConfig instead:

@ApplicationPath("/api")
@DeclareRoles({ UserRoles.USER, UserRoles.ADMIN })
@OpenAPIDefinition(info = @Info(title = "Backend service", version = "1.0.0"), servers = {
        @Server(url = "/backend", description = "localhost") })
public class ApplicationConfig extends ResourceConfig {

    public ApplicationConfig() {
        register(MultiPartFeature.class);

        register(MyExceptionMapper.class);
        // ... other ExceptionMappers

        register(AdminResource.class);
        register(UserResource.class);
        // ... other Resource classes
    }

}

I still need to do some configuration in my web.xml. According to this Stackoverflow thread I need to define the ResourceConfig in web.xml to use both of them together:

<servlet>
   <servlet-name>Backend</servlet-name>
   <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.mypackage.ApplicationConfig</param-value>
   </init-param>
   <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>com.mypackage.business.api</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>
</servlet>

Now the application runs, but I cannot reach any of the API endpoints because the automatically generated OpenAPI configuration is empty:

paths: {}
components: {}
stefanS
  • 312
  • 4
  • 17
  • You don't need a web.xml if you are using a ResourceConfig annotated with `@ApplicationPath` (as mentioned in your second stack overflow link). – Paul Samsotha Feb 05 '20 at 21:00
  • @PaulSamsotha I am defining my security roles and security constraints in `web.xml`. There might also be a way to configure this with annotations, but I would prefer not to touch a running system, especially as `web.xml` seems to have a few advantages (see https://stackoverflow.com/a/25564532/4602192). – stefanS Feb 06 '20 at 10:07
  • You don't need the definition. The one you have is not even correct. You are supposed to put your package in the param-value, but you simply have "jersey". I doubt that is your package name. That's why you don't have any paths. – Paul Samsotha Feb 06 '20 at 12:35
  • You are right, I did not pay attention there. I changed the param-value to the correct package name. Now when I delete my `web.xml`, the OpenAPI structure looks correct, but I get 404 errors for all endpoints. Probably because of the security config. Declaring the roles with a `@DeclareRoles` annotation is straight-forward, but the `@ServletSecurity` annotation seems to be tricky to work with. I will try to figure it out, but I would really prefer to keep my `web.xml`. – stefanS Feb 06 '20 at 15:56
  • Just delete the `` declaration, not the entire web.xml – Paul Samsotha Feb 06 '20 at 20:35
  • Tried it, but it breaks my OpenAPI configuration. Some of my endpoints now have a `/null/` path in the JSON file despite their `@Path` annotation, while others look just fine. It does not seem to be connected to interceptors or user roles. In any case I am receiving 404 errors for all endpoints, including login, although my server log tells me that it's actually working and creating a JSON Web Token. Maybe there is more that I need to register in my `ResourceConfig` constructor, but I would think that scanning the whole package with `packages("...");` should do the trick... – stefanS Feb 10 '20 at 14:37

0 Answers0