OpenAPITools / OpenAPITools/openapi-generator
[BUG][JAVA] oneOf/anyOf with discriminator generates model that picks only one subtype payload, ignoring others
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
[BUG][JAVA] oneOf/anyOf with discriminator generates model that picks only one subtype payload, ignoring others
Description
When using oneOf (or anyOf) with a discriminator on the payload property of a parent schema, the Java code generator produces a single model class that only represents one of the sub-schemas instead of properly generating a polymorphic type with all variants.
Scenario: I have a DeviceLifecycleEvent with a payload that can be either DeviceDataTransferEventPayload or DeviceCommModeStatusEventPayload, determined by a type discriminator field.
Expected behavior: The generator should produce:
- A parent/interface type for the payload (e.g.,
DeviceLifecycleEventPayload) with@JsonTypeInfoand@JsonSubTypesannotations - Two concrete subtype classes (
DeviceDataTransferEventPayloadandDeviceCommModeStatusEventPayload)
Actual behavior: The generator produces a single DeviceLifecycleEventPayload class that contains properties from only one of the two schemas (whichever is listed first or last), effectively ignoring the other variant entirely. No polymorphic annotations (@JsonTypeInfo/@JsonSubTypes) are generated.
This makes oneOf/anyOf with discriminator unusable for generating proper polymorphic Java models from OpenAPI 3.0.3 specs.
openapi-generator version
7.12.0 (via openapi-generator-maven-plugin)
OpenAPI declaration file content or url
openapi: 3.0.3
info:
version: v1
title: Device service events
paths: {}
components:
schemas:
DeviceLifecycleEvent:
type: object
description: Notification about device lifecycle events
required:
- type
- header
- payload
properties:
type:
type: string
enum:
- device_datatransfer_status_changed
- device_communication_mode_status_changed
header:
$ref: "#/components/schemas/DeviceMessageHeader"
payload:
oneOf:
- $ref: "#/components/schemas/DeviceDataTransferEventPayload"
- $ref: "#/components/schemas/DeviceCommModeStatusEventPayload"
discriminator:
propertyName: type
mapping:
device_datatransfer_status_changed: "#/components/schemas/DeviceDataTransferEventPayload"
device_communication_mode_status_changed: "#/components/schemas/DeviceCommModeStatusEventPayload"
DeviceMessageHeader:
type: object
required:
- ts
- correlationId
- deviceId
properties:
correlationId:
type: string
deviceId:
type: string
ts:
type: string
format: date-time
DeviceDataTransferEventPayload:
type: object
required:
- deviceId
- serialNumber
- updatedAt
- eventData
properties:
deviceId:
type: string
serialNumber:
type: string
updatedAt:
type: string
eventData:
$ref: "#/components/schemas/DeviceDataTransferEventData"
DeviceCommModeStatusEventPayload:
type: object
required:
- deviceId
- serialNumber
- updatedAt
- eventData
properties:
deviceId:
type: string
serialNumber:
type: string
updatedAt:
type: string
eventData:
$ref: "#/components/schemas/DeviceCommModeStatusEventData"
DeviceDataTransferEventData:
type: object
required:
- StatusDetails
properties:
StatusDetails:
type: object
properties:
dataTransfer:
type: object
properties:
status:
type: string
enum: [capable, incapable, Not Applicable]
statusReason:
type: string
updatedAt:
type: string
isMuted:
type: boolean
DeviceCommModeStatusEventData:
type: object
required:
- StatusDetails
properties:
StatusDetails:
type: object
properties:
communicationMode:
type: object
properties:
runtimeCommMode:
type: string
enum: [limited, normal]
updatedAt:
type: string
Generation Details
Maven plugin configuration:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.12.0</version>
<executions>
<execution>
<id>device-events</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/yaml/device-messages.yml</inputSpec>
<generatorName>java</generatorName>
<library>feign</library>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateModelDocumentation>false</generateModelDocumentation>
<generateApis>false</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateSupportingFiles>false</generateSupportingFiles>
<packageName>com.gehc.sto.device.event</packageName>
<modelPackage>com.gehc.sto.device.event</modelPackage>
<configOptions>
<openApiNullable>false</openApiNullable>
<interfaceOnly>true</interfaceOnly>
<useJakartaEe>true</useJakartaEe>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
Equivalent CLI command:
openapi-generator-cli generate \
-i device-messages.yml \
-g java \
--library feign \
--model-package com.example.event \
-p openApiNullable=false,interfaceOnly=true,useJakartaEe=true \
--global-property models
Steps to reproduce
- Create an OpenAPI 3.0.3 spec with a schema that uses
oneOf(oranyOf) on an inline property with adiscriminatorandmapping(see YAML above) - Generate Java models using
openapi-generator-maven-pluginv7.12.0 withjavagenerator andfeignlibrary - Inspect the generated
DeviceLifecycleEventPayload.java
Observed result:
DeviceLifecycleEventPayload.javais generated as a concrete class with fields from only one of the two payload schemas (e.g., onlyDeviceCommModeStatusEventPayloadfields)- No
@JsonTypeInfoor@JsonSubTypesannotations are present - The other payload type's unique fields are completely missing
- Effectively, one of the two
oneOfvariants is silently dropped
Expected result:
- Either a parent abstract class or interface
DeviceLifecycleEventPayloadwith@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")and@JsonSubTypeslisting both concrete types - Or proper generation of both concrete types that can be used polymorphically
Note: Using anyOf instead of oneOf produces the same broken result — a merged/flattened class that picks properties from only one variant.
Workaround that works: Using allOf with a discriminator on a shared parent schema generates correct polymorphic classes with @JsonTypeInfo + @JsonSubTypes. However, this changes the semantic meaning of the schema (inheritance vs. composition) and removes the payload property from the parent schema in documentation tools (Swagger UI).
Related issues/PRs
- https://github.com/OpenAPITools/openapi-generator/issues/10880 — oneOf not generating proper models
- https://github.com/OpenAPITools/openapi-generator/issues/12650 — discriminator with oneOf
- https://github.com/OpenAPITools/openapi-generator/issues/14917 — Java generator oneOf handling
Suggest a fix
The Java generator's oneOf/anyOf handling for inline properties (not top-level schemas) with a discriminator should:
- Generate a parent interface or abstract class (e.g.,
DeviceLifecycleEventPayload) annotated with@JsonTypeInfoand@JsonSubTypes - Each
oneOf/anyOfvariant should be generated as a concrete class implementing/extending that parent - The discriminator
mappingshould drive the@JsonSubTypes.Typeannotations
Currently, the generator seems to merge/flatten the oneOf variants into a single class, which defeats the purpose of oneOf with discriminator entirely. The allOf + discriminator path already handles this correctly for top-level schema inheritance — similar logic should be applied to inline oneOf/anyOf property discriminators.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the supplied device-messages.yml using the Java generator and inspect the generated DeviceLifecycleEventPayload.java. Compare the inline oneOf/anyOf output with the documented allOf workaround and related discriminator issues. Done means both payload variants are retained and polymorphic annotations are generated, with regression coverage if the repository's generator tests cover this path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi
- Domain
- backend-api-design, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100