[core] Resolve oneOf discriminator property type from child schemas
What
getDiscriminatorPropertyType resolved the discriminator property's type only from the oneOf/anyOf schema's own properties, defaulting to "string" otherwise. For a pure oneOf/anyOf interface whose discriminator property lives on a shared base the children inherit via allOf, this produced a String getter that clashed with the enum the subtypes actually expose.
This adds a fallback (in DiscriminatorUtils) that resolves the type from the mapped child schemas, chasing the property through each child's allOf members. It only fires when the previous code would have returned "string", so existing specs are unaffected — regenerating the full sample suite produces no diffs.
Scenarios covered
| Discriminator property declared… | Resolves to | Test |
|---|---|---|
As a $ref on the schema's own properties (unchanged path) | the referenced type (e.g. PetType) | DiscriminatorUtilsTest, DefaultCodegenTest |
Only on a shared base the oneOf children inherit via allOf | PetType (from children) | DiscriminatorUtilsTest, DefaultCodegenTest |
Only on a shared base the anyOf children inherit via allOf | PetType (from children) | DiscriminatorUtilsTest |
On a grandparent reached through multi-level allOf | PetType (recursive descent) | DiscriminatorUtilsTest |
As a plain inline string (no $ref, no enum) | "string" (fallback, unchanged) | DiscriminatorUtilsTest, DefaultCodegenTest |
Simples example where the discriminator is in the base object that is separate from the schema that contains oneOf
PetRequest:
type: object
oneOf:
- $ref: '#/components/schemas/CatRequest'
- $ref: '#/components/schemas/DogRequest'
discriminator:
propertyName: petType
mapping:
CAT: '#/components/schemas/CatRequest'
DOG: '#/components/schemas/DogRequest'
# Shared base WITHOUT a discriminator, so children flatten it via allOf
# instead of extending it (which would create a cyclical reference).
PetBase:
type: object
required:
- petType
- name
properties:
petType:
$ref: '#/components/schemas/PetType' # ---> This would be duplicated into PetRequest without this PR refactor
name:
type: string
CatRequest:
type: object
allOf:
- $ref: '#/components/schemas/PetBase'
- type: object
required:
- indoor
properties:
indoor:
type: boolean
DogRequest:
type: object
allOf:
- $ref: '#/components/schemas/PetBase'
- type: object
required:
- trained
properties:
trained:
type: boolean
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
(For Windows users, please run the script in WSL)./mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit
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
Fixes discriminator type resolution for oneOf/anyOf interfaces by deriving the property type from child schemas (via allOf) with cycle-safe recursion. Getter types now use the correct enum (e.g., PetType) instead of "string", avoiding interface vs subtype mismatches.
- Bug Fixes
- Updated
DiscriminatorUtils.getDiscriminatorPropertyType(OpenAPI, ...)to first check the schema’s own$ref, then fall back to oneOf/anyOf children viagetDiscriminatorPropertyTypeFromChildrenand recursivegetDiscriminatorSchemaDeep(supports multi-level allOf with a visited guard for cycles). - Updated
DefaultCodegen.getDiscriminatorPropertyTypeto passopenAPI, map to model names, and keep the "string" fallback. - Added
DiscriminatorUtilsTest, expandedDefaultCodegenTest, and new YAMLs (oneOf/anyOf, nested base, cyclic, string fallback). Regenerating samples shows no diffs.
- Updated