I am trying to create a set of POJOs from an OpenAPI specification that is generated from a pydantic data model. The problem I'm hitting is with discriminators. I am currently using the following configuration:
<cleanupOutput>false</cleanupOutput>
<generatorName>java</generatorName>
<modelPackage>com.model</modelPackage>
<generateApis>false</generateApis>
<generateApiDocumentation>false</generateApiDocumentation>
<generateApiTests>false</generateApiTests>
<generateSupportingFiles>false</generateSupportingFiles>
<generateApiTests>false</generateApiTests>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<configOptions>
<library>resttemplate</library>
<useJakartaEe>true</useJakartaEe>
<containerDefaultToNull>true</containerDefaultToNull>
<generateBuilders>true</generateBuilders>
<serializationLibrary>jackson</serializationLibrary>
<performBeanValidation>false</performBeanValidation>
<useBeanValidation>true</useBeanValidation>
<generateClientAsBean>false</generateClientAsBean>
<sortModelPropertiesByRequiredFlag>true</sortModelPropertiesByRequiredFlag>
<useOneOfInterfaces>true</useOneOfInterfaces>
<legacyDiscriminatorBehavior>false</legacyDiscriminatorBehavior>
</configOptions>
</configuration>
My Pydantic model is
from enum import Enum
from typing import Annotated, Literal, Union
from pydantic import BaseModel, Field
from typing_extensions import TypeAliasType
class PetType(Enum):
CAT = "cat"
DOG = "dog"
class Cat(BaseModel):
pet_type: Literal[PetType.CAT]
meows: int
class Dog(BaseModel):
pet_type: Literal[PetType.DOG]
barks: float
Pet = TypeAliasType('PetTypes', Annotated[Cat | Dog, Field(discriminator="pet_type")])
class Model(BaseModel):
pet: list[Pet] = Field(
...,
description="My Pets.",
)
This generates an OpenAPI spec (using from openapi_pydantic.util import construct_open_api_with_schema_class,with a made up endpoint) of:
openapi: 3.1.0
info:
title: Model
version: 0.1.0
paths:
/model:
post:
summary: Create Model
requestBody:
content:
application/json: {}
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/Model'
components:
schemas:
Cat:
properties:
pet_type:
type: string
const: cat
title: Pet Type
meows:
type: integer
title: Meows
type: object
required:
- pet_type
- meows
title: Cat
Dog:
properties:
pet_type:
type: string
const: dog
title: Pet Type
barks:
type: number
title: Barks
type: object
required:
- pet_type
- barks
title: Dog
Model:
properties:
pet:
items:
$ref: '#/components/schemas/PetTypes'
type: array
title: Pet
description: My Pets.
type: object
required:
- pet
title: Model
PetTypes:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
mapping:
cat: '#/components/schemas/Cat'
dog: '#/components/schemas/Dog'
Running mvn package will generate me an interface for discriminated values, and then concrete classes that extend that interface. But the getType() is incorrect. The interface has
public interface PetTypes {
public String getPetType();
}
But the implementations (Dog.java, Cat.java)have
public PetTypeEnum getPetType() {
return petType;
}
If I can get the generated OpenAPI schema to look like this, it generates the correct getPetType() methods, but I haven't been able to figure out how to get to here from the pydantic model.
openapi: 3.1.0
info:
title: Model
version: 0.1.0
paths:
/model:
post:
summary: Create Model
requestBody:
content:
application/json: {}
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/Model'
components:
schemas:
PetTypeEnum:
type: string
enum:
- cat
- dog
Cat:
properties:
pet_type:
$ref: '#/components/schemas/PetTypeEnum'
meows:
type: integer
title: Meows
type: object
required:
- pet_type
- meows
title: Cat
Dog:
properties:
pet_type:
$ref: '#/components/schemas/PetTypeEnum'
barks:
type: number
title: Barks
type: object
required:
- pet_type
- barks
title: Dog
Model:
properties:
pet:
items:
$ref: '#/components/schemas/PetTypes'
type: array
title: Pet
description: My Pets.
type: object
required:
- pet
title: Model
PetTypes:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
mapping:
cat: '#/components/schemas/Cat'
dog: '#/components/schemas/Dog'
I've found https://github.com/OpenAPITools/openapi-generator/issues/13484, https://github.com/OpenAPITools/openapi-generator/issues/12412 & https://github.com/pydantic/pydantic/issues/4337 but none are exactly referencing the issue I'm hitting. The last one seems to have been a fix that supports the references in the discriminator property. Turning off useOneOfInterfaces generates public class PetTypes with the superset of all the properties, but only Dog in the PetTypesEnum . Additionally, it seems to try to deserialize into the Cat.java and Dog.java classes, which then can't cast into the list of pets.
Any help would be appreciated.
Versions:
pydantic: 2.12.3
openapi-pydantic: 0.5.1
Open API spec: 3.1.0