@FormData Errors

310 views
Skip to first unread message

Jennifer Coston

unread,
Jun 29, 2016, 11:44:53 AM6/29/16
to Swagger
I tried to ask this question in the swagger IRC, but my connection keeps timing out so I thought I would ask it here as well.

I'm working on creating an api with a POST that accepts as input a jar file with source code, a configuration file, and some json defining the input object (in my case a plugin). However I've run into two errors. I initially had @Consumes set to multipart/form-data, as shown below, however, that would throw the error: java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded. So, I changed my @Consumes to application/x-www-form-urlencoded but now I'm getting a 415 error stating that there is a problem accessing /api/v1/analytic because there is an Unsupported Media Type. Did I make a mistake in creating this api? Am I allowed to have multiple FormDataParams? Is there a better way to pass in two files and some json?

Here is my api:

@POST
   
@Produces({ "application/json", "application/xml", "application/avro" })
   
@Consumes({"multipart/form-data"})
   
@io.swagger.annotations.ApiOperation(value = "Upload plugin", notes = "This can only be done by the logged in user.", response = void.class, tags={ "plugin", })
   
@io.swagger.annotations.ApiResponses(value = {
       
@io.swagger.annotations.ApiResponse(code = 200, message = "successful operation", response = void.class) })
   
public Response createPlugin(@ApiParam(value = "Uploaded Plugin", required=true)@FormParam("json")  String json,
           
@FormDataParam("file") InputStream jarInputStream,
           
@FormDataParam("file") FormDataContentDisposition jarFileDetail,
           
@FormDataParam("file") InputStream configInputStream,
           
@FormDataParam("file") FormDataContentDisposition configFileDetail,@Context SecurityContext securityContext)
   
throws NotFoundException {
       
return delegate.createPlugin(json,jarInputStream, jarFileDetail,configInputStream, configFileDetail,securityContext);
   
}

Example Json:

{
  "pluginD": "1234",
  "status": "active",
  "jarFileName": "pluginA.jar",
  "configFileName": "pluginA.properties",
}


Implementation method:

@Override
   
public Response createPlugin(String json, InputStream jarInputStream, FormDataContentDisposition jarFileDetail,
           
InputStream configInputStream, FormDataContentDisposition configFileDetail, SecurityContext securityContext)
                   
throws NotFoundException {

       
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK,
               
"Plugin" + "TBD" + " has been added")).build();
}



tony tam

unread,
Jun 29, 2016, 11:46:13 AM6/29/16
to swagger-sw...@googlegroups.com
FormData parameters are really picky sometimes.  What version of Jersey are you using?  And what are your dependencies?

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jennifer Coston

unread,
Jun 29, 2016, 12:07:12 PM6/29/16
to Swagger
I'm using Jersey version 2.22.1, Jetty version 9.3.6.v20151106, and Jackson version 2.4.2

Here are all of my Jerse, Jetty, and Json Dependencies. My pom file is quite extensive so let me know if you need to see any other dependencies.

<!-- Jersey Dependencies -->
       
<dependency>
           
<groupId>org.glassfish.jersey.media</groupId>
           
<artifactId>jersey-media-multipart</artifactId>
           
<version>${jersey2-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.glassfish.jersey.media</groupId>
           
<artifactId>jersey-media-json-jackson</artifactId>
           
<version>${jersey2-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.glassfish.jersey.containers</groupId>
           
<artifactId>jersey-container-servlet</artifactId>
           
<version>${jersey2-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.glassfish.jersey.containers</groupId>
           
<artifactId>jersey-container-servlet-core</artifactId>
           
<version>${jersey2-version}</version>
       
</dependency>
       
       
<!-- Jetty Dependencies -->
       
<dependency>
           
<groupId>org.eclipse.jetty</groupId>
           
<artifactId>jetty-server</artifactId>
           
<version>${jetty-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.eclipse.jetty</groupId>
           
<artifactId>jetty-servlet</artifactId>
           
<version>${jetty-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.eclipse.jetty</groupId>
           
<artifactId>jetty-webapp</artifactId>
           
<version>${jetty-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.eclipse.jetty</groupId>
           
<artifactId>jetty-annotations</artifactId>
           
<version>${jetty-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>org.eclipse.jetty</groupId>
           
<artifactId>jetty-plus</artifactId>
           
<version>${jetty-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>javax.servlet</groupId>
           
<artifactId>javax.servlet-api</artifactId>
           
<version>3.1.0</version>
           
<scope>compile</scope>
       
</dependency>
       
<dependency>
           
<groupId>javax.ejb</groupId>
           
<artifactId>javax.ejb-api</artifactId>
           
<version>3.2</version>
       
</dependency>
       
       
<!-- JSON processing: jackson -->
       
<dependency>
           
<groupId>com.fasterxml.jackson.core</groupId>
           
<artifactId>jackson-core</artifactId>
           
<version>${jackson-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>com.fasterxml.jackson.core</groupId>
           
<artifactId>jackson-annotations</artifactId>
           
<version>${jackson-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>com.fasterxml.jackson.core</groupId>
           
<artifactId>jackson-databind</artifactId>
           
<version>${jackson-version}</version>
       
</dependency>
       
<dependency>
           
<groupId>com.fasterxml.jackson.datatype</groupId>
           
<artifactId>jackson-datatype-joda</artifactId>
           
<version>2.1.5</version>
       
</dependency>
       
<dependency>
           
<groupId>joda-time</groupId>
           
<artifactId>joda-time</artifactId>
           
<version>2.2</version>
       
</dependency>
       
<!-- Dependency for processing avro with jackson -->
       
<dependency>
           
<groupId>com.fasterxml.jackson.dataformat</groupId>
           
<artifactId>jackson-dataformat-avro</artifactId>
           
<version>2.7.4</version>
       
</dependency>
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

Jennifer Coston

unread,
Jun 30, 2016, 9:40:41 AM6/30/16
to Swagger
Hi Tony,

I never heard back from you so I'm guessing you may need more information. So here is my code for the pluginAPI so far, at the moment I'm trying to get the put to work.

package com.my.company.swagger.api;

import io.swagger.annotations.ApiParam;
import com.my.company.swagger.api.AnalyticApiService;
import com.my.company.MyApp;
import com.my.company.swagger.api.util.NotFoundException;

import java.io.InputStream;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.*;


@Path("/plugin")
@io.swagger.annotations.Api(value ="Plugin", description = "the Plugin API")
@javax.annotation.Generated(value = "class com.my.company.codegen.MyCodegenGenerator", date = "2016-06-28T11:12:52.731-04:00")
@RequiresPermissions("protected:read")
public class PluginApi  {
   
private final PluginpiService delegate = (AnalyticApiService) MyApp.getApplicationContext().getBean("AnalyticApiService");


   
@POST
   
@Produces({ "application/json", "application/xml", "application/avro" })

   
@Consumes({"application/x-www-form-urlencoded"})
   
@io.swagger.annotations.ApiOperation(value = "Upload Plugin", notes = "This can only be done by the logged in user.", response = void.class, tags={ "Plugin", })

   
@io.swagger.annotations.ApiResponses(value = {
       
@io.swagger.annotations.ApiResponse(code = 200, message = "successful operation", response = void.class) })

   
public Response createAnalytic(@ApiParam(value = "Uploaded Plugin", required=true)@FormParam("json")  String json,
           
@FormDataParam("jarfile") InputStream jarInputStream,
           
@FormDataParam("jarfileinfo") FormDataContentDisposition jarFileDetail,
           
@FormDataParam("configfile") InputStream configInputStream,
           
@FormDataParam("configfileinfo") FormDataContentDisposition configFileDetail,@Context SecurityContext securityContext)
   
throws NotFoundException {
       
return delegate.createAnalytic(json,jarInputStream, jarFileDetail,configInputStream, configFileDetail,securityContext);
   
}
   
}


Here is my plugin class:

package com.my.company.swagger.api;

import java.util.Objects;
@javax.annotation.Generated(value = "class com.my.company.codegen.IafCodegenGenerator", date = "2016-06-28T11:12:52.731-04:00")
public class Plugin   {
 
 
private String pluginID = null;
 
private String status = null;
 
private String jarFileName = null;
 
private String configFileName = null;

 
/**
   **/

 
public Plugin pluginID(String pluginID) {
   
this.pluginID = pluginID;
   
return this;
 
}

 
 
@ApiModelProperty(value = "")
 
@JsonProperty("pluginID")
 
public String getAnalyticID() {
   
return pluginID;
 
}
 
public void setAnalyticID(String pluginID) {
   
this.pluginID = pluginID;
 
}

 
/**
   * Plugin Status
   **/

 
public Plugin status(String status) {
   
this.status = status;
   
return this;
 
}

 
 
@ApiModelProperty(value = "Plugin Status")
 
@JsonProperty("status")
 
public String getStatus() {
   
return status;
 
}
 
public void setStatus(String status) {
   
this.status = status;
 
}

 
/**
   **/

 
public Plugin jarFileName(String jarFileName) {
   
this.jarFileName = jarFileName;
   
return this;
 
}

 
 
@ApiModelProperty(value = "")
 
@JsonProperty("jarFileName")
 
public String getJarFileName() {
   
return jarFileName;
 
}
 
public void setJarFileName(String jarFileName) {
   
this.jarFileName = jarFileName;
 
}

 
/**
   **/

 
public Plugin configFileName(String configFileName) {
   
this.configFileName = configFileName;
   
return this;
 
}

 
 
@ApiModelProperty(value = "")
 
@JsonProperty("configFileName")
 
public String getConfigFileName() {
   
return configFileName;
 
}
 
public void setConfigFileName(String configFileName) {
   
this.configFileName = configFileName;
 
}


 
@Override
 
public boolean equals(Object o) {
   
if (this == o) {
     
return true;
   
}
   
if (o == null || getClass() != o.getClass()) {
     
return false;
   
}
   
Plugin Plugin = (Plugin) o;
   
return Objects.equals(pluginID, Plugin.pluginID) &&
       
Objects.equals(status, Plugin.status) &&
       
Objects.equals(jarFileName, Plugin.jarFileName) &&
       
Objects.equals(configFileName, Plugin.configFileName);
 
}

 
@Override
 
public int hashCode() {
   
return Objects.hash(pluginID, status, jarFileName, configFileName);
 
}

 
@Override
 
public String toString() {
   
StringBuilder sb = new StringBuilder();
    sb
.append("class Plugin {\n");
   
    sb
.append("    pluginID: ").append(toIndentedString(pluginID)).append("\n");
    sb
.append("    status: ").append(toIndentedString(status)).append("\n");
    sb
.append("    jarFileName: ").append(toIndentedString(jarFileName)).append("\n");
    sb
.append("    configFileName: ").append(toIndentedString(configFileName)).append("\n");
    sb
.append("}");
   
return sb.toString();
 
}

 
/**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */

 
private String toIndentedString(Object o) {
   
if (o == null) {
     
return "null";
   
}
   
return o.toString().replace("\n", "\n    ");
 
}
}



Thanks!
-Jennifer




On Wednesday, June 29, 2016 at 12:07:12 PM UTC-4, Jennifer Coston wrote:
I'm using Jersey version 2.22.1, Jetty version 9.3.6.v20151106, and Jackson version 2.4.2

Here are all of my Jersey, Jetty, and Json Dependencies. My pom file is quite extensive so let me know if you need to see any other dependencies.

tony tam

unread,
Jun 30, 2016, 12:33:09 PM6/30/16
to swagger-sw...@googlegroups.com
Hi, for Jersey 2.x, you need to enable a multipart reader in your web.xml like such:

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

My guess is you’ve done the other steps but not that one.  Please also note that you must use multipart for file-uploads in swagger.

web.xml:

<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
io.swagger.sample.resource
</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>
<init-param>
<param-name>jersey.config.server.wadl.disableWadl</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Resource method:
  @POST
@Path("/{petId}/uploadImage")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@Produces({MediaType.APPLICATION_JSON})
@ApiOperation(value = "uploads an image",
response = io.swagger.sample.model.ApiResponse.class)
public Response uploadFile(
@ApiParam(value = "ID of pet to update", required = true) @PathParam("petId") Long petId,
@ApiParam(value = "Additional data to pass to server") @FormDataParam("additionalMetadata") String testString,
@ApiParam(value = "file to upload") @FormDataParam("file") InputStream inputStream,
@ApiParam(value = "file detail") @FormDataParam("file") FormDataContentDisposition fileDetail) {
...
}



To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

Jennifer Coston

unread,
Jun 30, 2016, 1:00:15 PM6/30/16
to Swagger
Hi Tony,

Thanks for getting back to me. I actually already have the multipart reader enabled. It turns out if I change the annotation for the string from @FormParam to @FormDataParam then the errors go away.

Thanks!
Jennifer

tony tam

unread,
Jun 30, 2016, 1:01:38 PM6/30/16
to swagger-sw...@googlegroups.com
OK great

To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages