swagger-codegen-generators icon indicating copy to clipboard operation
swagger-codegen-generators copied to clipboard

[Spring] Support MultiPartFile for file uploads

Open jglynn opened this issue 5 years ago • 17 comments

Somewhat similar to https://github.com/swagger-api/swagger-codegen-generators/issues/150 but for Spring specifically.

When using the Spring profile and a multipart service definition, I would expect to be able to influence the generated api Controller stub to use Spring's org.springframework.web.multipart.MultiPartFile.

The options I've tried and result:

  • type: string, format: binary maps to a byte[]
  • type: file, format: binary maps to a org.springframework.core.io.Resource (I would expect this to use MultiPartFile instead)

As an alternative, I extended the SpringCodegen and registered my own typeMapping.

typeMapping.put{"multiPartFile","MultiPartFile");
importMapping.put("MultiPartFile", "org.springframework.web.multipart.MultiPartFile");

With this I was able to get a controller stub generated using the MultiPartFile and support uploads. I'm pretty new to this product so I'm not sure if this is a best practice or not.

jglynn avatar Sep 25 '18 15:09 jglynn

@lion7 - given your experience and solution for #150 I'd be curious to get your perspective on the Spring flavor for the same use case.

jglynn avatar Sep 25 '18 20:09 jglynn

@jglynn I submitted a pull request (actually 2 different ways of solving this) that should fix this issue. A long story short: the binary type is not interpreted correctly which causes the MultiPartFile class to not be used. The code is actually there but due to this bug it is ignored.

The PR's are https://github.com/swagger-api/swagger-codegen-generators/pull/184 and https://github.com/swagger-api/swagger-codegen-generators/pull/185

lion7 avatar Sep 26 '18 12:09 lion7

Thanks @lion7! FWIW, #184 is pretty slick but it seems like #185 would be the preferred approach for consistency with the specification terminology across the codebase.

jglynn avatar Oct 03 '18 19:10 jglynn

@lion7 #184 works with the spring (spring-boot) generator, #185 only generates File istead of MultipartFile as parameter

Andy2003 avatar Nov 14 '18 10:11 Andy2003

I also used a work around. With the swagger-codegen-maven-plugin

<typeMappings> <typeMapping>multipartFile=org.springframework.web.multipart.MultipartFile</typeMapping> </typeMappings>

mistriel avatar Mar 03 '19 17:03 mistriel

@mistriel could you elaborate how you made it work, including your yaml schema example? Because this typemapping does nothing on our side.

shathor avatar May 23 '19 12:05 shathor

@shathor this is the relevant part from my YAML :

/media/upload:
    post:
      tags:
        - media
      summary: Upload media file to storage
      operationId: uploadFile
      produces:
        - application/json
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                required: true
                file:
                  type: multipartFile
                  required: true
                classification:
                  required: true
                  $ref: '#/components/schemas/MediaClassification'
                visibility:
                  required: true
                  $ref: '#/components/schemas/Visibility'

Note that i also downloaded the entire templates and used them as part of the maven build :

<properties>
		<checkstyle.skip>true</checkstyle.skip><!-- set to true since code is generated -->
		<findbugs.skip>true</findbugs.skip><!-- set to true since code is generated -->
		<swagger.resources>${project.basedir}/src/main/resources/swagger/</swagger.resources>
</properties>

<plugin>
				<groupId>io.swagger.codegen.v3</groupId>
				<artifactId>swagger-codegen-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>generate swagger</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<inputSpec>${swagger.resources}/app-server-api.yaml</inputSpec>
							<language>spring</language>
							<templateDirectory>${swagger.resources}/templates/</templateDirectory>
						
							<generateApiTests>false</generateApiTests>
							<generateModelTests>false</generateModelTests>
							<generateSupportingFiles>false</generateSupportingFiles>
							<typeMappings>
								<typeMapping>multipartFile=org.springframework.web.multipart.MultipartFile</typeMapping>
							</typeMappings>
							<configOptions>
								<sourceFolder>src/main/java</sourceFolder>
								<modelPackage>xxx.xxx.xxx.payload</modelPackage>
								<apiPackage>xxx.xxx.xxx.api</apiPackage>
								<dateLibrary>java8</dateLibrary>
								<java8>true</java8>
								<interfaceOnly>true</interfaceOnly>
								<library>spring-mvc</library>
								<delegatePattern>false</delegatePattern>
								<useTags>true</useTags>
								<hideGenerationTimestamp>true</hideGenerationTimestamp>
							</configOptions>
						</configuration>
					</execution>
				</executions>
			</plugin>

And mainly customized the api.mustache file make sure it imports :

import org.springframework.web.multipart.MultipartFile;

mistriel avatar May 25 '19 21:05 mistriel

I see, thanks a lot. I was hoping to get by without modifying the templates.

shathor avatar May 26 '19 12:05 shathor

I see, thanks a lot. I was hoping to get by without modifying the templates.

Sorry, the rest of it is protected by our IP, yet this should do the work for you.

mistriel avatar May 26 '19 12:05 mistriel

I got another workaround. In the maven build add:

<typeMappings>
    <typeMapping>File=org.springframework.core.io.InputStreamSource</typeMapping>
</typeMappings>

The YAML part:

requestBody:
content:
  multipart/form-data:
	schema:
	  type: object
	  properties:
		file:
		  type: string
		  format: binary
		myOtherProperty:
		  $ref: '#/components/schemas/MyType'
		  type: string
	  required:
		- file
		- myOtherProperty

shathor avatar Jun 12 '19 16:06 shathor

PR https://github.com/swagger-api/swagger-codegen-generators/pull/184 got merged a few days ago so this should be fixed in the next release

lion7 avatar Jun 12 '19 16:06 lion7

@jglynn PR #185 is now also merged. I would suggest closing this issue :)

lion7 avatar Jan 04 '20 09:01 lion7

Using version 3.0.19 I still have to use the workarround

<typeMappings>
  <typeMapping>multipartFile=org.springframework.web.multipart.MultipartFile</typeMapping>
</typeMappings>

to have a MutlipartFile when I want an array of file in the requestBody.

documents:
          type: array
          items:
            type: multipartFile
            format: binary

sebastianblesgen avatar Feb 01 '21 18:02 sebastianblesgen

Seems the problem is still present.

natami avatar Nov 29 '21 07:11 natami

  1. The problem is still here

  1. The problem is still here

david139 avatar Nov 13 '23 06:11 david139

The problem is still here

taylorzhangyx avatar Apr 01 '24 14:04 taylorzhangyx