[core] Add introspection support for discovering the discriminator type in a oneOf allOf polymorphic structure

Merged
MA
3mo ago
+470-27

This PR adds so that the useOneOfInterfaces setting properly supports when the discriminator is an enum for the case where the discriminator is inherited in a oneOf -> allOf scenario.

Fixes https://github.com/OpenAPITools/openapi-generator/issues/22541, https://github.com/OpenAPITools/openapi-generator/issues/18693, https://github.com/OpenAPITools/openapi-generator/issues/19194, https://github.com/OpenAPITools/openapi-generator/issues/9048

Summary

This PR introduces so that the discriminator discovering (done in method recursiveGetDiscriminator) not only finds the property carrying the discriminator, but also the property's type. This gives the interface creator the opportunity to ensure that its discriminator type field aligns with that of the implementing children.

Example scenario

For example given the specification:

openapi: 3.1.0
info:
  title: Polymorphism example with oneOf, allOf and enum-discriminator
  version: "1.0"
paths:
  /pets:
    get:
      operationId: getAllPets
      responses:
        "200":
          content:
            application/json:
              schema:
                type: array
                items:
                  oneOf:
                    - $ref: "#/components/schemas/Cat"
                    - $ref: "#/components/schemas/Dog"
          description: Success
components:
  schemas:
    PetType:
      type: string
      enum:
        - Cat
        - Dog
    Pet:
      type: object
      discriminator:
        propertyName: petType
      properties:
        petType:
          $ref: '#/components/schemas/PetType'
      required:
        - petType
    Cat:
      description: A representation of a cat
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            huntingSkill:
              type: string
              description: The measured skill for hunting
              enum:
                - clueless
                - lazy
                - adventurous
                - aggressive
          required:
            - huntingSkill
    Dog:
      description: A representation of a dog
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            packSize:
              type: integer
              format: int32
              description: the size of the pack the dog is from
              default: 0
              minimum: 0
          required:
            - packSize

where a oneOf containing both children exists. The children in turn references a parent (Pet) that in turn defines the discriminator value as an enum (PetType).

With the current generator, the property type of the parent is not considered, so the generated interface has type String, while the children have the enum PetType. This means that the code does not compile.

This type of structure is what you natively get with swagger-core and springdoc when using @JsonSubTypes for polymorphism in an array-context. So out-of-the-box support would be very useful.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Adds introspection to discover discriminator property types inherited through oneOf/allOf (enum refs, inline enums, and formatted strings like URI) so generated oneOf interfaces and models use the correct type instead of String. Fixes compile errors with useOneOfInterfaces when the discriminator is defined on a parent and referenced by children.

  • New Features
    • recursiveGetDiscriminator now returns DiscriminatorData (discriminator + resolved schema). DefaultCodegen uses it to set CodegenDiscriminator.propertyType from $ref, inline enums (via toEnumName), or formatted strings (e.g., URI via getTypeDeclaration).
    • Validates oneOf alternatives share the same discriminator name and type; logs warnings on conflicts.
    • Adds cross-generator tests (Java resttemplate, Helidon MP, Micronaut, Spring, Kotlin Spring) and expands the 3.0 sample spec to cover enum-ref, inline enum, and string format: uri inheritance cases.