Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Generated file upload api takes MimeMultipart instead of FormDataMultipart #105

Closed
sumveds opened this issue Jun 16, 2015 · 6 comments
Closed

Comments

@sumveds
Copy link

sumveds commented Jun 16, 2015

This is how my photo upload API spec looks like:

/photos:
      description: User profile photo resource.
      post:
        description: Upload profile photo resource of the user.
        headers:
          Content-Type: 
            required: true
        body:
          multipart/form-data:
            formParameters:
              photo:
                description: Photo to be uploaded
                required: true
                type: file
        responses:
          202:
            description: Accepted

When I run the raml-to-jaxrs plugin, it generates the interface which takes MimeMultipart as the body object.

    @POST
    @Path("{userId}/photos")
    @Consumes("multipart/form-data")
    @Produces({
        "application/json"
    })
    UsersResource.PostUsersByUserIdPhotosResponse postUsersByUserIdPhotos(
        @PathParam("userId")
        Long userId,
        @HeaderParam("Content-Type")
        @NotNull
        String contentType, MimeMultipart entity)
        throws Exception
    ;

When I run fire this api from the client, then it gives me 415 Unsupported media type response and the following is the exception:

MessageBodyReader not found for media type=multipart/form-data, type=class javax.mail.internet.MimeMultipart, genericType=class javax.mail.internet.MimeMultipart.

Is it possible to generate interface method with FormDataMultipart instead of MimeMultipart?

Regards,
Sumved

@ddossot
Copy link

ddossot commented Jun 16, 2015

com.sun.jersey.multipart.FormDataMultiPart is a Jersey-specific class. The code generator targets standard JDK/EE/JAX-RS classes only.

This said I don't think the 415 response comes from there, it is more likely that the client doesn't POST a multipart/form-data request. What client do you use? Can you check its logs to see what content-type is used for the request?

@KonstantinSviridov
Copy link
Contributor

Hi, @sumveds

As @ddossot has said, generator should produce MimeMultipart by default.

But you can make it produce whatever you want by means of so called Generator Extensions.

First, create a class similar to the following one:

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;

import org.raml.jaxrs.codegen.core.ext.GeneratorExtension;
import org.raml.model.Action;
import org.raml.model.MimeType;
import org.raml.model.Raml;
import org.raml.model.Resource;
import org.raml.model.parameter.AbstractParam;

import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;


public class MultipartExtension implements GeneratorExtension {

    private JCodeModel codeModel;

    public void onCreateResourceInterface(JDefinedClass resourceInterface,
            Resource resource) {}

    public void onAddResourceMethod(
            JMethod method,
            Action action,
            MimeType bodyMimeType,
            Collection<MimeType> uniqueResponseMimeTypes) {
        List<JVar> params = method.params();
        if(params!=null&&!params.isEmpty()){
            for(JVar param : params){
                JType paramType = param.type();
                if(paramType!=null&&paramType.fullName().equals("javax.mail.internet.MimeMultipart")){
                    JClass clazz = codeModel.ref("com.sun.jersey.multipart.FormDataMultiPart");
                    param.type(clazz);
                }
            }
        }
    }

    public boolean AddParameterFilter(String name, AbstractParam parameter,
            Class<? extends Annotation> annotationClass, JMethod method) {
        return true;
    }

    public void setRaml(Raml raml) {}

    public void setCodeModel(JCodeModel codeModel) {
        this.codeModel = codeModel;
    }
}

Then add this class as an extension to the generator plugin configuration iside pom.xml:

<plugin>
                <groupId>org.raml.plugins</groupId>
                <artifactId>raml-jaxrs-maven-plugin</artifactId>
                <version>1.3.4-SNAPSHOT</version>
                <configuration>
                    <sourceDirectory>${basedir}/raml</sourceDirectory>
                    <outputDirectory>${basedir}/src/main/java</outputDirectory>
                    <basePackageName>org.raml.jaxrs.example</basePackageName>
                    <jaxrsVersion>2.0</jaxrsVersion>
                    <useJsr303Annotations>false</useJsr303Annotations>
                    <jsonMapper>jackson1</jsonMapper>
                    <removeOldOutput>true</removeOldOutput>
                    <extensions>
                        <extension>custom.extension.MultipartExtension</extension>
                    </extensions>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-sources</phase>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
<!-- In my case the extension class is contained inside the raml-for-jaxrs-examples-aux project, so I add this dependency -->
                        <groupId>raml-for-jaxrs-examples</groupId>
                        <artifactId>raml-for-jaxrs-examples-aux</artifactId>
                        <version>0.0.1-SNAPSHOT</version>
                    </dependency>
                </dependencies>
            </plugin>

Please, pull the latest commits from 1.3.4-SNAPSHOT and make sure that your extension class is passed into the plugins classpath.

Regards,
Konstantin

@sumveds
Copy link
Author

sumveds commented Jul 2, 2015

Hi @KonstantinSviridov

Sorry for the late response. Do I also need to add a dependency in my pom file?

I am unable to find the below classes in the classpath:

import org.raml.jaxrs.codegen.core.ext.GeneratorExtension;
import org.raml.model.Action;
import org.raml.model.MimeType;
import org.raml.model.Raml;
import org.raml.model.Resource;
import org.raml.model.parameter.AbstractParam;

import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;

I am trying to write this custom extension class in my project itself. Is this way correct?

Regards,
Sumved

@KonstantinSviridov
Copy link
Contributor

Hi, @sumveds

Does the project which contains your extension has the folowing dependency:

<dependency>
  <groupId>org.raml</groupId>
  <artifactId>raml-jaxrs-codegen-core</artifactId>
  <version>1.3.4-SNAPSHOT</version>
</dependency>

?
In my case it makes available all the classes in your list.

Regards, Konstantin

@sumveds
Copy link
Author

sumveds commented Jul 5, 2015

Hi @KonstantinSviridov

Changing AddParameterFilter from false to true stops generating FormDataMultiPart class. Can you please look into this and let me know?

Regards,
Sumved

@sumveds
Copy link
Author

sumveds commented Jul 5, 2015

My plugin configuration looks something like below:

<plugin>
    <groupId>org.raml.plugins</groupId>
    <artifactId>raml-jaxrs-maven-plugin</artifactId>
    <version>1.3.4-SNAPSHOT</version>
    <configuration>
        <sourceDirectory>${basedir}/src/main/resources/api/v1.0</sourceDirectory>
        <basePackageName>com.helpchat.api</basePackageName>
        <jaxrsVersion>2.0</jaxrsVersion>
        <useJsr303Annotations>true</useJsr303Annotations>
        <jsonMapperConfiguration>
            <useLongIntegers>true</useLongIntegers>
        </jsonMapperConfiguration>
        <jsonMapper>jackson2</jsonMapper>
        <removeOldOutput>true</removeOldOutput>
        <outputDirectory>${project.build.directory}/java-gen</outputDirectory>
        <extensions>
            <extension>com.helpchat.api.ext.MultipartExtension</extension>
        </extensions>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <phase>generate-sources</phase>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>com.helpchat.api.ext</groupId>
            <artifactId>api-interface-ext</artifactId>
            <version>0.0.2-SNAPSHOT</version>
        </dependency>
    </dependencies>
</plugin>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants