Open grassehh opened 7 months ago
@grassehh did you find a work around?.
I have used a workaround where I drop the "oneOf" from the parent and leave just the "discriminator". See the Pet, Cat, Dog, Lizard example at https://swagger.io/specification/v3/#discriminator-object
I have used a workaround where I drop the "oneOf" from the parent and leave just the "discriminator". See the Pet, Cat, Dog, Lizard example at https://swagger.io/specification/v3/#discriminator-object
The problem I see with this workaround is that your specification is not compliant as the documentation states The discriminator object is legal only when using one of the composite keywords oneOf, anyOf, allOf
@mike-adonis currently our workaround is quite straightforward. We override dataClass.mustache
and dataClassReqVar.mustache
templates by setting the templateDir
variable of the plugin in our gradle.kts
file:
templateDir.set("$projectDir/docs/templates")
The drawback is that it requires us to rebase the templates everytime we bump the plugin version.
As of 7.8.0, here are our templates for the kotlin-spring
plugin:
dataclass.mustache:
/**
* {{{description}}}
{{#vars}}
* @param {{name}} {{{description}}}
{{/vars}}
*/{{#discriminator}}
{{>typeInfoAnnotation}}{{/discriminator}}
{{#additionalModelTypeAnnotations}}
{{{.}}}
{{/additionalModelTypeAnnotations}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{.}}}
{{/vendorExtensions.x-class-extra-annotation}}
{{#discriminator}}interface {{classname}}{{/discriminator}}{{^discriminator}}{{#hasVars}}data {{/hasVars}}class {{classname}}(
{{#requiredVars}}
{{>dataClassReqVar}}{{^-last}},
{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}},
{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>dataClassOptVar}}{{^-last}},
{{/-last}}{{/optionalVars}}
) {{/discriminator}}{{#vendorExtensions.x-implements}}{{#-first}}: {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}}{
{{#discriminator}}{{#model.vendorExtensions.x-discriminator-type}}{{>modelMutable}} {{{discriminator.propertyName}}}: {{{model.vendorExtensions.x-discriminator-type}}}{{/model.vendorExtensions.x-discriminator-type}}{{/discriminator}}
{{#hasEnums}}{{#vars}}{{#isEnum}}
/**
* {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
enum class {{{nameInPascalCase}}}(@get:JsonValue val value: {{#isContainer}}{{#items}}{{{dataType}}}{{/items}}{{/isContainer}}{{^isContainer}}{{{dataType}}}{{/isContainer}}) {
{{#allowableValues}}{{#enumVars}}
{{{name}}}({{{value}}}){{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}};
companion object {
@JvmStatic
@JsonCreator
fun forValue(value: {{#isContainer}}{{#items}}{{{dataType}}}{{/items}}{{/isContainer}}{{^isContainer}}{{{dataType}}}{{/isContainer}}): {{{nameInPascalCase}}} {
return values().first{it -> it.value == value}
}
}
}
{{/isEnum}}{{/vars}}{{/hasEnums}}
{{#serializableModel}}
companion object {
private const val serialVersionUID: kotlin.Long = 1
}
{{/serializableModel}}
}
dataClassReqVar.mustache:
{{#useBeanValidation}}{{>beanValidation}}{{>beanValidationModel}}{{/useBeanValidation}}{{#swagger2AnnotationLibrary}}
@Schema({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}required = true, {{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
@ApiModelProperty({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}required = true, {{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}{{#vendorExtensions.x-field-extra-annotation}}
{{{.}}}{{/vendorExtensions.x-field-extra-annotation}}
@get:JsonProperty("{{{baseName}}}", required = true){{#vendorExtensions.x-overrides}} override{{/vendorExtensions.x-overrides}} {{>modelMutable}} {{{name}}}: {{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}}?{{/isNullable}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}
Then in the openapi.yaml
:
We add x-overrides
property in the definition of the properties which are overriden by the child classes. Example:
type: string
x-overrides: true
description: my child property
We add x-implements
property in the definition of each subclass. Example:
type: object
x-implements: [ "MyParentClass" ]
description: My child class
properties:
...
schema:
title: Parent
oneOf:
- $ref: '#/components/schemas/child1'
- $ref: '#/components/schemas/child2'
discriminator:
propertyName: discriminatorProperty
mapping:
type1: 'child1'
type2: 'child2'
fyi. there's a new option called generateOneOfAnyOfWrappers
for better oneOf/anyOf support: https://openapi-generator.tech/docs/generators/kotlin/
please give it a try to see if it better meet your requirement
The problem I see with this workaround is that your specification is not compliant as the documentation states
The discriminator object is legal only when using one of the composite keywords oneOf, anyOf, allOf
The spec I linked is not mine, it is a sample from the actual OpenAPi 3 documentation.
And the linked spec uses allOf in the child classes meeting the legality constraint for the discriminator object.
fyi. there's a new option called
generateOneOfAnyOfWrappers
for better oneOf/anyOf support: https://openapi-generator.tech/docs/generators/kotlin/please give it a try to see if it better meet your requirement
I tried that option beginning of June 2024 but the results were not usable. Have there been improvements on it since then?
fyi. there's a new option called
generateOneOfAnyOfWrappers
for better oneOf/anyOf support: https://openapi-generator.tech/docs/generators/kotlin/please give it a try to see if it better meet your requirement
I just tried the generateOneOfAnyOfWrappers option but it generated uncompilable code. There are errors such as "Unresolved reference 'TypeAdapterFactory'".
I'm having the same experience. I'm using kotlinx.serialization
and seems like generateOneOfAnyOfWrappers
forces GSON, which makes it incompilable.
Bug Report Checklist
Description
Hi, I'm not certain is this is a bug or a feature since a few things seems to works correctly. When using polymorphism with discriminator exactly as documented on OpenAPI 3.0 specifications, the following of the generated code is incorrect:
override
keyword on parent interface discriminator propertyNote: The same issue is noticeable when using
kotlin-spring
generatoropenapi-generator version
7.4.0
OpenAPI declaration file content or url
https://github.com/grassehh/openapi-generator-experiments/blob/main/openapi.yaml
Generation Details
Checkout this repository and build using
gradle build
. The generated code is in thebuild
directory.Steps to reproduce
Simply generate the Kotlin code as explained above then read the generated code in
build
directory.Related issues/PRs
Suggest a fix