OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.42k stars 6.48k forks source link

[BUG] Different behavior in "spring" and "kotlin-spring" generators #9065

Open Truyaka opened 3 years ago

Truyaka commented 3 years ago

I have YAML for generation:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
  - url: http://localhost:8021
    description: Local server url
paths:
  /coverages/policy-type:
    get:
      tags:
        - policy-type
      operationId: findAll
      parameters:
        - name: pageable
          in: query
          required: true
          schema:
            $ref: '#/components/schemas/Pageable'
      responses:
        "200":
          description: OK
          content:
            'application/json':
              schema:
                $ref: '#/components/schemas/PagePolicyTypeDto'

And I have plugin for server-generation with replacement import by org.springframework.data.domain.Pageable:

<plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>5.0.0</version>
                <configuration>
                    <generatorName>kotlin-spring</generatorName>
                    <apiPackage>my</apiPackage>
                    <modelPackage>my.dto</modelPackage>
                    <generateApiTests>false</generateApiTests>
                    <generateModelTests>false</generateModelTests>
                    <configOptions>
                        <gradleBuildFile>false</gradleBuildFile>
                        <useTags>true</useTags>
                        <!--<library>spring-mvc</library>-->
                        <interfaceOnly>true</interfaceOnly>
                    </configOptions>
                </configuration>
                <executions>
                    <execution>
                        <id>policy-type-api-generator</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/resources/api/PolicyTypeApi.yaml</inputSpec>
                            <importMappings>
                                Pageable=org.springframework.data.domain.Pageable,
                                PagePolicyTypeDto=my.dto.PolicyTypePageImpl
                            </importMappings>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

And I have different code result in kotlin-spring generation:

    @GetMapping(
        value = ["/coverages/policy-type"],
        produces = ["application/json"]
    )
    fun findAll(@NotNull @RequestParam(value = "pageable", required = true) pageable: Pageable
    ): ResponseEntity<PolicyTypePageImpl> {
        return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
    }

spring generation:

    @ApiOperation(value = "", nickname = "findAll", notes = "", response = PolicyTypePageImpl.class, tags={ "policy-type", })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "OK", response = PolicyTypePageImpl.class) })
    @GetMapping(
        value = "/coverages/policy-type",
        produces = { "application/json" }
    )
    default ResponseEntity<PolicyTypePageImpl> findAll(@NotNull @ApiParam(value = "", required = true) @Valid org.springframework.data.domain.Pageable pageable) {
        getRequest().ifPresent(request -> {
            for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
                if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
                    String exampleString = "{ \"number\" : 7, \"numberOfElements\" : 1, \"last\" : true, \"size\" : 2, \"totalPages\" : 0, \"pageable\" : { \"size\" : 1, \"page\" : 0, \"sort\" : [ \"sort\", \"sort\" ] }, \"sort\" : { \"unsorted\" : true, \"sorted\" : true, \"empty\" : true }, \"first\" : true, \"content\" : [ { \"id\" : 0, \"title\" : \"title\" }, { \"id\" : 0, \"title\" : \"title\" } ], \"totalElements\" : 6, \"empty\" : true }";
                    ApiUtil.setExampleResponse(request, "application/json", exampleString);
                    break;
                }
            }
        });
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

    }

There is a difference in @NotNull @ApiParam(value = "", required = true) @Valid org.springframework.data.domain.Pageable pageable and @NotNull @RequestParam(value = "pageable", required = true) pageable: Pageable

In kotlin-case expects param with "pageable"-name, BUT it's the just wrapper for params "page", "size" and "sort" that present in org.springframework.data.domain.Pageable Spring-behavior (without openapi generators) is such as "spring"-generator

And second mini-question: is there any way to use generic org.springframework.data.domain.Page with code-generation? I tried to replace by importMappings but it doesn't support generic types

MaksimMyshkin commented 3 years ago

As I found out there is custom parameter for OpenAPI file (https://github.com/OpenAPITools/openapi-generator/pull/5022) that allow handle Pageable in a special way. But this parameter exists only for Java Spring generator. I think this feature just need to be (re)implemented for spring-kotlin.

On our project we have a messy workaround that replaces Pageable to custom DTO. Would be nice to support Pageable natively.