swagger-codegen
swagger-codegen copied to clipboard
[SPRING][SPRING-CLOUD] Bug generating invoker for request params with style: form and explode: true
Description
When defining a query param with type object, style: form and explode: true the wrong invoker code is generated:
@ApiOperation(value = "", nickname = "getBooks", notes = "", response = Book.class, responseContainer = "List", tags = { "book", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful operation", response = Book.class, responseContainer = "List") })
@RequestMapping(value = "/book",
produces = "application/json",
method = RequestMethod.GET)
default ResponseEntity<List<Book>> getBooks(@ApiParam(value = "") @Valid @RequestParam(value = "pagination", required = false) Pagination pagination) {
// omitted implementation details
}
This declaration will not work with spring boot, given the following curl generated via swagger editor:
curl -X 'GET' \
'https://editor.swagger.io/codegen/book?page=0&size=15' \
-H 'accept: application/json'
Swagger-codegen version
swagger-codegen-maven-plugin 3.0.52
Swagger declaration file content or url
paths:
/codegen/book:
get:
operationId: getBooks
tags:
- book
parameters:
- name: pagination
in: query
schema:
type: object
properties:
page:
type: integer
size:
type: integer
example:
{
"page": 0,
"size": 15
}
style: form
explode: true
(full file, rename extension to yaml) api.yaml
Command line used for generation
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-library</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<spring-boot.version>3.2.1</spring-boot.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
<jackson.version>2.15.3</jackson.version>
<swagger-codegen-plugin.version>3.0.52</swagger-codegen-plugin.version>
<openapi.package>${project.groupId}.library</openapi.package>
<openapi.model.package>${openapi.package}.api</openapi.model.package>
<openapi.client.package>${openapi.package}.client</openapi.client.package>
<openapi.invoker.package>${openapi.package}.invoker</openapi.invoker.package>
<openapi.file.name>api.yaml</openapi.file.name>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.client</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.19</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>13.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>io.swagger.codegen.v3</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>${swagger-codegen-plugin.version}</version>
<executions>
<execution>
<id>java-model-generation</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<language>spring</language>
<library>spring-cloud</library>
<generateApis>true</generateApis>
<generateSupportingFiles>true</generateSupportingFiles>
<inputSpec>${project.basedir}/src/main/resources/${openapi.file.name}</inputSpec>
<output>${project.build.directory}/generated-sources/swagger</output>
<modelPackage>${openapi.model.package}</modelPackage>
<apiPackage>${openapi.client.package}</apiPackage>
<invokerPackage>${openapi.invoker.package}</invokerPackage>
<configOptions>
<generateForOpenFeign>true</generateForOpenFeign>
<dateLibrary>java8</dateLibrary>
<sourceFolder>src/main/java</sourceFolder>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<annotationLibrary>swagger3</annotationLibrary>
<serializableModel>true</serializableModel>
<serializationLibrary>jackson</serializationLibrary>
<additionalEnumTypeAnnotations>true</additionalEnumTypeAnnotations>
<useJakartaEe>true</useJakartaEe>
<useSpringBoot3>true</useSpringBoot3>
<useEnumCaseInsensitive>true</useEnumCaseInsensitive>
</configOptions>
<typeMappings>
<typeMapping>Double=java.math.BigDecimal</typeMapping>
</typeMappings>
<importMappings>
<importMapping>GregorianCalendar=java.util.GregorianCalendar</importMapping>
</importMappings>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>io.swagger.codegen.v3</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create a maven project with the following directory structure:
my-library
├── pom.xml
├── src
├── main
├── resources
├── api.yaml
Run:
mvn install
And check ./$OUTPUT_DIR/generated-sources/swagger/src/main/java/com/example/library/client/BookApi.java
Suggest a fix/enhancement
When a query param with type object, style: form and explode: true is used, the generated method param should omit @RequestParam annotation, since spring will automatically do the correct conversion.
@ApiOperation(value = "", nickname = "getBooks", notes = "", response = Book.class, responseContainer = "List", tags = { "book", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful operation", response = Book.class, responseContainer = "List") })
@RequestMapping(value = "/book",
produces = "application/json",
method = RequestMethod.GET)
default ResponseEntity<List<Book>> getBooks(Pagination pagination) {
// omitted implementation details
}