[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 @JsonTypeInfo and @JsonSubTypes annotations
- Two concrete subtype classes (
DeviceDataTransferEventPayload and DeviceCommModeStatusEventPayload)
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 (or anyOf) on an inline property with a discriminator and mapping (see YAML above)
- Generate Java models using
openapi-generator-maven-plugin v7.12.0 with java generator and feign library
- Inspect the generated
DeviceLifecycleEventPayload.java
Observed result:
DeviceLifecycleEventPayload.java is generated as a concrete class with fields from only one of the two payload schemas (e.g., only DeviceCommModeStatusEventPayload fields)
- No
@JsonTypeInfo or @JsonSubTypes annotations are present
- The other payload type's unique fields are completely missing
- Effectively, one of the two
oneOf variants is silently dropped
Expected result:
- Either a parent abstract class or interface
DeviceLifecycleEventPayload with @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") and @JsonSubTypes listing 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
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 @JsonTypeInfo and @JsonSubTypes
- Each
oneOf/anyOf variant should be generated as a concrete class implementing/extending that parent
- The discriminator
mapping should drive the @JsonSubTypes.Type annotations
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.
[BUG][JAVA]
oneOf/anyOfwith discriminator generates model that picks only one subtype payload, ignoring othersDescription
When using
oneOf(oranyOf) with adiscriminatoron thepayloadproperty 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
DeviceLifecycleEventwith apayloadthat can be eitherDeviceDataTransferEventPayloadorDeviceCommModeStatusEventPayload, determined by atypediscriminator field.Expected behavior: The generator should produce:
DeviceLifecycleEventPayload) with@JsonTypeInfoand@JsonSubTypesannotationsDeviceDataTransferEventPayloadandDeviceCommModeStatusEventPayload)Actual behavior: The generator produces a single
DeviceLifecycleEventPayloadclass 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/anyOfwith discriminator unusable for generating proper polymorphic Java models from OpenAPI 3.0.3 specs.openapi-generator version
7.12.0(viaopenapi-generator-maven-plugin)OpenAPI declaration file content or url
Generation Details
Maven plugin configuration:
Equivalent CLI command:
Steps to reproduce
oneOf(oranyOf) on an inline property with adiscriminatorandmapping(see YAML above)openapi-generator-maven-pluginv7.12.0 withjavagenerator andfeignlibraryDeviceLifecycleEventPayload.javaObserved result:
DeviceLifecycleEventPayload.javais generated as a concrete class with fields from only one of the two payload schemas (e.g., onlyDeviceCommModeStatusEventPayloadfields)@JsonTypeInfoor@JsonSubTypesannotations are presentoneOfvariants is silently droppedExpected result:
DeviceLifecycleEventPayloadwith@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")and@JsonSubTypeslisting both concrete typesNote: Using
anyOfinstead ofoneOfproduces the same broken result — a merged/flattened class that picks properties from only one variant.Workaround that works: Using
allOfwith 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 thepayloadproperty from the parent schema in documentation tools (Swagger UI).Related issues/PRs
Suggest a fix
The Java generator's
oneOf/anyOfhandling for inline properties (not top-level schemas) with adiscriminatorshould:DeviceLifecycleEventPayload) annotated with@JsonTypeInfoand@JsonSubTypesoneOf/anyOfvariant should be generated as a concrete class implementing/extending that parentmappingshould drive the@JsonSubTypes.TypeannotationsCurrently, the generator seems to merge/flatten the
oneOfvariants into a single class, which defeats the purpose ofoneOfwith discriminator entirely. TheallOf+ discriminator path already handles this correctly for top-level schema inheritance — similar logic should be applied to inlineoneOf/anyOfproperty discriminators.