[kotlin-server] Add configurable inheritance modes#24090
Conversation
There was a problem hiding this comment.
3 issues found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="docs/generators/kotlin-server.md">
<violation number="1" location="docs/generators/kotlin-server.md:37">
P2: Default description for `inheritanceMode` uses non-existent library label `javalin`; should match the concrete supported library values `javalin5`/`javalin6`.</violation>
<violation number="2" location="docs/generators/kotlin-server.md:37">
P2: The `inheritanceMode` documentation does not document the cross-option restriction that `library=jaxrs-spec` with `inheritanceMode=sealed` is rejected at generation time, which can mislead users into a guaranteed failing configuration.</violation>
</file>
<file name="modules/openapi-generator/src/main/resources/kotlin-server/libraries/jaxrs-spec/data_class.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-server/libraries/jaxrs-spec/data_class.mustache:44">
P1: Parent constructor argument forwarding is only applied to the non-serializable/non-parcelize branch; the serializableModel and parcelizeModels parent branches still extend the parent with no arguments, breaking compilation when an abstract parent has constructor parameters.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| {{#required}}{{>data_class_sealed_var}}{{/required}}{{^required}}{{>data_class_sealed_var}}{{/required}}{{^-last}},{{/-last}} | ||
|
|
||
| {{/allVars}} | ||
| ){{/x-inheritance-mode-abstract}}{{/discriminator}}{{#parent}}{{^serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{^serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{^parcelizeModels}} : Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{^serializableModel}}{{#parcelizeModels}} : Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{#parcelizeModels}} : Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#vendorExtensions.x-has-data-class-body}} { |
There was a problem hiding this comment.
P1: Parent constructor argument forwarding is only applied to the non-serializable/non-parcelize branch; the serializableModel and parcelizeModels parent branches still extend the parent with no arguments, breaking compilation when an abstract parent has constructor parameters.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/kotlin-server/libraries/jaxrs-spec/data_class.mustache, line 44:
<comment>Parent constructor argument forwarding is only applied to the non-serializable/non-parcelize branch; the serializableModel and parcelizeModels parent branches still extend the parent with no arguments, breaking compilation when an abstract parent has constructor parameters.</comment>
<file context>
@@ -29,22 +29,28 @@ import java.io.Serializable
+{{#required}}{{>data_class_sealed_var}}{{/required}}{{^required}}{{>data_class_sealed_var}}{{/required}}{{^-last}},{{/-last}}
+
+{{/allVars}}
+){{/x-inheritance-mode-abstract}}{{/discriminator}}{{#parent}}{{^serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{^serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{^parcelizeModels}} : Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{^serializableModel}}{{#parcelizeModels}} : Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{#parcelizeModels}} : Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#vendorExtensions.x-has-data-class-body}} {
{{/vendorExtensions.x-has-data-class-body}}
{{#serializableModel}}
</file context>
| ){{/x-inheritance-mode-abstract}}{{/discriminator}}{{#parent}}{{^serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{^serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}, Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{^parcelizeModels}} : Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{^serializableModel}}{{#parcelizeModels}} : Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{#parcelizeModels}} : Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#vendorExtensions.x-has-data-class-body}} { | |
| ){{/x-inheritance-mode-abstract}}{{/discriminator}}{{#parent}}{{^serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{^parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}, Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{^serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#parent}}{{#serializableModel}}{{#parcelizeModels}} : {{{parent}}}{{#vendorExtensions.x-parent-ctor-args}}({{{.}}}){{/vendorExtensions.x-parent-ctor-args}}{{^vendorExtensions.x-parent-ctor-args}}{{#isMap}}(){{/isMap}}{{#isArray}}(){{/isArray}}{{/vendorExtensions.x-parent-ctor-args}}, Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{^parcelizeModels}} : Serializable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{^serializableModel}}{{#parcelizeModels}} : Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}{{#parcelizeModels}} : Serializable, Parcelable{{/parcelizeModels}}{{/serializableModel}}{{/parent}}{{#vendorExtensions.x-has-data-class-body}} { |
| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| | ||
| |implicitHeaders|Skip header parameters in the generated API methods.| |false| | ||
| |interfaceOnly|Whether to generate only API interface stubs without the server files. This option is currently supported only when using jaxrs-spec library.| |false| | ||
| |inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)| |
There was a problem hiding this comment.
P2: Default description for inheritanceMode uses non-existent library label javalin; should match the concrete supported library values javalin5/javalin6.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/generators/kotlin-server.md, line 37:
<comment>Default description for `inheritanceMode` uses non-existent library label `javalin`; should match the concrete supported library values `javalin5`/`javalin6`.</comment>
<file context>
@@ -34,6 +34,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|implicitHeaders|Skip header parameters in the generated API methods.| |false|
|interfaceOnly|Whether to generate only API interface stubs without the server files. This option is currently supported only when using jaxrs-spec library.| |false|
+|inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)|
|library|library template (sub-template)|<dl><dt>**ktor**</dt><dd>ktor framework</dd><dt>**ktor2**</dt><dd>ktor (2.x) framework</dd><dt>**jaxrs-spec**</dt><dd>JAX-RS spec only</dd><dt>**javalin5**</dt><dd>Javalin 5</dd><dt>**javalin6**</dt><dd>Javalin 6</dd></dl>|ktor|
|modelMutable|Create mutable models| |false|
</file context>
| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| | ||
| |implicitHeaders|Skip header parameters in the generated API methods.| |false| | ||
| |interfaceOnly|Whether to generate only API interface stubs without the server files. This option is currently supported only when using jaxrs-spec library.| |false| | ||
| |inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)| |
There was a problem hiding this comment.
P2: The inheritanceMode documentation does not document the cross-option restriction that library=jaxrs-spec with inheritanceMode=sealed is rejected at generation time, which can mislead users into a guaranteed failing configuration.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/generators/kotlin-server.md, line 37:
<comment>The `inheritanceMode` documentation does not document the cross-option restriction that `library=jaxrs-spec` with `inheritanceMode=sealed` is rejected at generation time, which can mislead users into a guaranteed failing configuration.</comment>
<file context>
@@ -34,6 +34,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|implicitHeaders|Skip header parameters in the generated API methods.| |false|
|interfaceOnly|Whether to generate only API interface stubs without the server files. This option is currently supported only when using jaxrs-spec library.| |false|
+|inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)|
|library|library template (sub-template)|<dl><dt>**ktor**</dt><dd>ktor framework</dd><dt>**ktor2**</dt><dd>ktor (2.x) framework</dd><dt>**jaxrs-spec**</dt><dd>JAX-RS spec only</dd><dt>**javalin5**</dt><dd>Javalin 5</dd><dt>**javalin6**</dt><dd>Javalin 6</dd></dl>|ktor|
|modelMutable|Create mutable models| |false|
</file context>
| |inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)| | |
| |inheritanceMode|Strategy for model inheritance generation. Values: `none`, `sealed`, `abstract`, `composition`. Note: `sealed` is not supported when `library=jaxrs-spec`.|<dl><dt>**none**</dt><dd>Flatten inheritance metadata (no discriminator/parent shaping).</dd><dt>**sealed**</dt><dd>Use sealed/interface-oriented shaping.</dd><dt>**abstract**</dt><dd>Use abstract base class shaping.</dd><dt>**composition**</dt><dd>Flatten inheritance and generate discriminator owners as composition wrappers (`value: Any`).</dd></dl>|sealed (ktor/javalin), abstract (jaxrs-spec)| |
Summary
This change adds configurable inheritance handling to the
kotlin-servergenerator, includingjaxrs-spec.Fixes
Added option
inheritanceModenonesealedabstractcompositionDefault behavior
ktor/javalin*default tosealedjaxrs-specdefaults toabstractValidation
inheritanceModevaluesjaxrs-spec + sealedImplementation details
Codegen option plumbing
In
KotlinServerCodegen:inheritanceModestatex-inheritance-mode-nonex-inheritance-mode-sealedx-inheritance-mode-abstractx-inheritance-mode-compositionModel post-processing
Added mode-aware model shaping in
postProcessAllModels:nonecompositionvalue: kotlin.Anysealed/abstractTemplate updates
Shared
kotlin-servermodel templatesealed classin sealed modeabstract classin abstract modejaxrs-specmodel templatesabstract classinstead ofinterfaceoverridex-parent-ctor-argsTests
Added/updated coverage in
KotlinServerCodegenTestfor:sealedmode forktorabstractmode forjaxrs-specjaxrs-spec + sealedrejectioncompositionnonenonecompositionDocumentation
Updated
docs/generators/kotlin-server.mdwith the newinheritanceModeoption and mode descriptions.Verification
Tested with: