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.3k stars 6.44k forks source link

[BUG][Java][Spring] Incorrect generated code when use application/x-www-form-urlencoded and oneOf #14967

Open jorgerod opened 1 year ago

jorgerod commented 1 year ago

Bug Report Checklist

Description

I am designing an API following the oauth2 protocol. In it, the encoding to use is application/x-wwww-form-urlencoded.

Using that encoding algorithm and oneOf feature is not generating the code correctly.

openapi-generator version

6.4.0

OpenAPI declaration file content or url

Minimal sample

openapi: '3.0.0'
info:
  title: AuthServer OAuth2
  description: This API contains the public paths for the Auth Server
  version: 0.0.6
security:
  - basicOauthClientAuth: [ ]
paths:
  /oauth2/token:
    post:
      description: Generate OAuth2/OIDC tokens
      operationId: token
      security:
        - basicOauthClientAuth: [ ]
      tags:
        - OAuth2
      requestBody:
        description: OAuth2 RO basics grant types
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              oneOf:
                - $ref: '#/components/schemas/PasswordGrantTypeForm'
                - $ref: '#/components/schemas/AnonymousGrantTypeForm'
              discriminator:
                propertyName: grant_type
                mapping:
                  password: '#/components/schemas/PasswordGrantTypeForm'
                  anonymous: '#/components/schemas/AnonymousGrantTypeForm'
      responses:
        '200':
          description: OAuth2/OIDC standard response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessTokenResponse'

components:
  securitySchemes:
    basicOauthClientAuth:
      description: Base64 of the clientId and clientSecret, the format is clientId:clientSecret
      type: http
      scheme: basic
  schemas:
    GrantType:
      type: object
      required:
        - grant_type
      properties:
        grant_type:
          type: string
          description: Grant type to obtain the token.
          example: "password"

    PasswordGrantTypeForm:
      title: PasswordGrantTypeForm
      description: Request body for access token with password grant type for ecommerce customers
      allOf:
        - $ref: '#/components/schemas/GrantType'
        - type: object
          properties:
            scope:
              description: List of scope for the token separated by an space
              type: string
              example: "session openid"
            username:
              type: string
              description: Account id of the user
              example: "4b4d91f2-17b9-46af-b5de-008956ee6f65"
            password:
              type: string
              description: Password of the user
              example: "dummyP4ssw0rd"
          required:
            - username
            - password

    AnonymousGrantTypeForm:
      title: AnonymousGrantTypeForm
      description: Request body for access token with anonymous grant type for ecommerce customers
      allOf:
        - $ref: '#/components/schemas/GrantType'
        - type: object
          properties:
            scope:
              description: List of scope for the token separated by an space
              type: string
              example: "session openid"
            anonymous:parameters:account_id:
              type: string
              description: Account id of the user
              example: "4b4d91f2-17b9-46af-b5de-008956ee6f65"
          required:
            - anonymous:parameters:account_id

    AccessTokenResponse:
      type: object
      required:
        - token_type
      properties:
        token_type:
          type: string
        id_token:
          type: string
          description: If the request includes openid scope this field contains a JWT token    
Generation Details

java -jar openapi-generator-cli.jar generate -i spec.yml -g spring -o out --global-property skipFormModel=false

Steps to reproduce
  1. Generate classes
  2. See OauthApi.java.
Output
  1. It has been created endpoint with all parameters
  2. Parameters username and password are created as required --> incorrect
  3. Discriminator (grandType) should be required --> incorrect
/**
     * POST /oauth2/token
     * Generate OAuth2/OIDC tokens
     *
     * @param username Account id of the user (required)
     * @param password Password of the user (required)
     * @param grantType Grant type to obtain the token. (optional)
     * @param scope List of scope for the token separated by an space (optional)
     * @param anonymousColonParametersColonAccountId Account id of the user (optional)
     * @return OAuth2/OIDC standard response (status code 200)
     */
    @Operation(
        operationId = "token",
        description = "Generate OAuth2/OIDC tokens",
        tags = { "OAuth2" },
        responses = {
            @ApiResponse(responseCode = "200", description = "OAuth2/OIDC standard response", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = AccessTokenResponse.class))
            })

        },
        security = {
            @SecurityRequirement(name = "basicOauthClientAuth")
        }
    )
    @RequestMapping(
        method = RequestMethod.POST,
        value = "/oauth2/token",
        produces = { "application/json" },
        consumes = { "application/x-www-form-urlencoded" }
    )
    default ResponseEntity<AccessTokenResponse> token(
        @Parameter(name = "username", description = "Account id of the user", required = true) @Valid @RequestParam(value = "username", required = true) String username,
        @Parameter(name = "password", description = "Password of the user", required = true) @Valid @RequestParam(value = "password", required = true) String password,
        @Parameter(name = "grant_type", description = "Grant type to obtain the token.") @Valid @RequestParam(value = "grant_type", required = false) String grantType,
        @Parameter(name = "scope", description = "List of scope for the token separated by an space") @Valid @RequestParam(value = "scope", required = false) String scope,
        @Parameter(name = "anonymous:parameters:account_id", description = "Account id of the user") @Valid @RequestParam(value = "anonymous:parameters:account_id", required = false) String anonymousColonParametersColonAccountId
    )

Expected

I was expecting the input parameters to be like when the encoding is application/json.

/**
     * POST /oauth2/token
     * Generate OAuth2/OIDC tokens
     *
     * @param tokenRequest OAuth2 RO basics grant types (required)
     * @return OAuth2/OIDC standard response (status code 200)
     */
    @Operation(
        operationId = "token",
        description = "Generate OAuth2/OIDC tokens",
        tags = { "OAuth2" },
        responses = {
            @ApiResponse(responseCode = "200", description = "OAuth2/OIDC standard response", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = AccessTokenResponse.class))
            })
        },
        security = {
            @SecurityRequirement(name = "basicOauthClientAuth")
        }
    )
    @RequestMapping(
        method = RequestMethod.POST,
        value = "/oauth2/token",
        produces = { "application/json" },
        consumes = { "application/x-www-form-urlencoded" }
    )
    default ResponseEntity<AccessTokenResponse> token(
        @Parameter(name = "TokenRequest", description = "OAuth2 RO basics grant types", required = true) @Valid @RequestBody TokenRequest tokenRequest
    )
MiguelAngelLV commented 1 year ago

Any advances?

My problem is when I create a application/x-www-form-urlencoded, any field of my object is create as parameter of method with @RequestParam and only works by url param, but not as form param.

If I change the definition and I make a class with my params with @RquestParams, it works fine.

ALEXB6924 commented 5 months ago

Hi. Has this been fixed in any way?