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
22.05k stars 6.61k forks source link

[BUG][SPRING] Spring generator not creating query parameter objects with @ParameterObject annotation #12709

Open hnitzsche opened 2 years ago

hnitzsche commented 2 years ago

Bug Report Checklist

Description

If I generate spring code with springoc annotation provider from an OpenAPI spec where an operation is defined that contains an object as query parameter I expect this object being annotated with @ParameterObject or have a possibility to do so.

openapi-generator version
OpenAPI declaration file content or url
openapi: 3.0.0
info:
  title: Query object as @ParameterObject
  version: '1.0'
servers:
  - url: http://localhost:8080
tags:
  - name: "Book"

paths:
  /books:
    get:
      tags:
        - "Book"
      summary: Get all Books
      operationId: getAllBooks
      x-spring-paginated: true
      parameters:
        - name: BookFilter
          in: query
          schema:
            type: object
            properties:
              name:
                type: string
              author:
                type: string
      responses:
        '200':
          description: A list of Books
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Book"
components:
  schemas:
    Book:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        author:
          type: string
Generation Details

java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \ -i above_file.yaml \ -g spring \ -o /generated-output

Steps to reproduce

Output is:


/**
     * GET /books : Get all Books
     *
     * @param bookFilter  (optional)
     * @return A list of Books (status code 200)
     */
    @Operation(
        operationId = "getAllBooks",
        summary = "Get all Books",
        tags = { "Book" },
        responses = {
            @ApiResponse(responseCode = "200", description = "A list of Books", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = Book.class))
            })
        }
    )
    @RequestMapping(
        method = RequestMethod.GET,
        value = "/books",
        produces = { "application/json" }
    )
    default ResponseEntity<List<Book>> getAllBooks(
        @Parameter(name = "BookFilter", description = "") @Valid GetAllBooksBookFilterParameter bookFilter,
        @ParameterObject final Pageable pageable
    ) {
        getRequest().ifPresent(request -> {
            for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
                if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
                    String exampleString = "{ \"author\" : \"author\", \"name\" : \"name\", \"id\" : 0 }";
                    ApiUtil.setExampleResponse(request, "application/json", exampleString);
                    break;
                }
            }
        });
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

    }
Related issues/PRs
Suggest a fix

I suggest annotating the request parameter object with ParameterObject instead of Parameter like this:


/**
     * GET /books : Get all Books
     *
     * @param bookFilter  (optional)
     * @return A list of Books (status code 200)
     */
    @Operation(
        operationId = "getAllBooks",
        summary = "Get all Books",
        tags = { "Book" },
        responses = {
            @ApiResponse(responseCode = "200", description = "A list of Books", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = Book.class))
            })
        }
    )
    @RequestMapping(
        method = RequestMethod.GET,
        value = "/books",
        produces = { "application/json" }
    )
    default ResponseEntity<List<Book>> getAllBooks(
        @ParameterObject @Valid GetAllBooksBookFilterParameter bookFilter,
        @ParameterObject final Pageable pageable
    ) {
        getRequest().ifPresent(request -> {
            for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
                if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
                    String exampleString = "{ \"author\" : \"author\", \"name\" : \"name\", \"id\" : 0 }";
                    ApiUtil.setExampleResponse(request, "application/json", exampleString);
                    break;
                }
            }
        });
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

    }

Would appreciate if someone could make a suggestion to make this possible or comment with any concerns about this.

drndos commented 5 months ago

Workaround: annotate the method parameter in implementation

@Overrride
public ResponseEntity<List<Book>> getAllBooks(@ParameterObject GetAllBooksBookFilterParameter bookFilter, @ParameterObject Pageable pageable) {