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][Spring] code generation fails if oneOf discriminator is enum #19194

Open jan-mawh opened 2 months ago

jan-mawh commented 2 months ago

Bug Report Checklist

Description

I want to limit the possible entries for the discriminator using oneOf. Therefore i want to set the discriminator as enum (See OpenAPI declaration file) below.

The openapi-generator-maven-plugin says: [WARNING] 'cargoParent' defines discriminator 'unit', but the referenced schema 'TONS' is incorrect. invalid type for unit, set it to string and the code finally fails to compile.

The Problem is that the generator creates the method

public TonsUnitEnum getUnit() {
    return unit;
  }

in the TONS.java class. But the CargoParents requires a method returning String:

public interface CargoParent {
    String getUnit();
}
openapi-generator version

openapi-generator-maven-plugin 7.7.0

OpenAPI declaration file content or url
openapi: 3.0.3
info:
  title: test
  contact:
    email: support@company.de
  license:
    name: company Licence
    url: https://company.de/
  version: 0.1.1
servers:
  - url: https://webservice.company.org
paths:
  /doSomething:
    post:
      summary: test
      description: description for test operation
      operationId: doSomething
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/doSomethingRequest'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/doSomethingResponse'
components:
  schemas:
    doSomethingRequest:
      title: doSomethingRequest
      type: object
      properties:
        cargo:
          $ref: '#/components/schemas/cargoParent'
      required:
        - cargo
    doSomethingResponse:
      title: doSomethingResponse
      type: object
    TonsUnitEnum:
      type: string
      enum:
        - Tons
    TONS:
      title: TONS
      type: object
      properties:
        unit:
          $ref: '#/components/schemas/TonsUnitEnum'
        amount:
          type: number
          format: double
          example: 40
          minimum: 0
      required:
        - unit
        - amount
    KILOGRAMS:
      title: KILOGRAMS
      type: object
      properties:
        unit:
          type: string
          pattern: ^KILOGRAMS$
          example: KILOGRAMS
        amount:
          type: number
          format: double
          example: 1000
          minimum: 0
      required:
        - unit
        - amount
    cargoParent:
      title: cargoParent
      type: object
      oneOf:
        - $ref: '#/components/schemas/TONS'
        - $ref: '#/components/schemas/KILOGRAMS'
      discriminator:
        propertyName: unit
        mapping:
          TONS: '#/components/schemas/TONS'
          KILOGRAMS: '#/components/schemas/KILOGRAMS'
Related issues/PRs

https://github.com/OpenAPITools/openapi-generator/issues/12412

jan-mawh commented 2 months ago

bye the way: when removing the enum from TonsUnitEnum everything works fine. So with:

TonsUnitEnum:
      type: string

code compiles perfectly

michael-adjaye-nutmeg commented 1 week ago

bye the way: when removing the enum from TonsUnitEnum everything works fine. So with:

TonsUnitEnum:
      type: string

code compiles perfectly

But does the data type on your concrete class become a String after removing the enum from TonsUnitEnum? This is what happens for me - which is not ideal...

jan-mawh commented 1 week ago

But does the data type on your concrete class become a String after removing the enum from TonsUnitEnum? This is what happens for me - which is not ideal...

Yes it becomes a string - which is (as you already mentioned) not ideal. I would like it to be an enum. I figured out a workaround using a regex pattern (see example with KILOGRAMS) - but this is also not ideal:

    KILOGRAMS:
      title: KILOGRAMS
      type: object
      properties:
        unit:
          type: string
          pattern: ^KILOGRAMS$
          example: KILOGRAMS

Below is an even better example why i would like to use an enum. TONS and KILOGRAMS both include cargoGeneralParameter with an allOf. And cargoGeneralParameter has the unit discrimitator which should either be "TONS " or "KILOGRAMS " - that's why an enum would be much better than a string:

openapi: 3.0.3
info:
  title: test
  contact:
    email: support@company.de
  license:
    name: company Licence
    url: https://company.de/
  version: 0.1.1
servers:
  - url: https://webservice.company.org
paths:
  /doSomething:
    post:
      summary: test
      description: description for test operation
      operationId: doSomething
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/doSomethingRequest'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/doSomethingResponse'
components:
  schemas:
    doSomethingRequest:
      title: doSomethingRequest
      type: object
      properties:
        cargo:
          $ref: '#/components/schemas/cargoInterface'
      required:
        - cargo
    doSomethingResponse:
      title: doSomethingResponse
      type: object
    cargoInterface:
      oneOf:
        - $ref: '#/components/schemas/TONS'
        - $ref: '#/components/schemas/KILOGRAMS'
      discriminator:
        propertyName: unit
    TONS:
      allOf:
        - $ref: '#/components/schemas/cargoGeneralParameter'
        - type: object
          properties:
            amount:
              type: integer
          required:
            - amount
    KILOGRAMS:
      allOf:
        - $ref: '#/components/schemas/cargoGeneralParameter'
        - type: object
          properties:
            amount:
              type: number
              format: double
              example: 1000
              minimum: 0
          required:
            - amount
    cargoGeneralParameter:
      type: object
      properties:
        unit:
          type: string
          enum:
            - KILOGRAMS
            - TONS
        cargoId:
          type: integer
      required:
        - unit
        - cargoId