Skip to content

Conversation

Picazsoo
Copy link
Contributor

@Picazsoo Picazsoo commented Sep 11, 2025

This PR adds support for two new vendor extensions named x-kotlin-implements and x-kotlin-implements-fields.

  • x-kotlin-implements - a list of fully qualified interface(s) that should be implemented by a DTO
  • x-kotlin-implements-fields - a list of fields that are backed by the interface(s). This is necessary because unlike java, one has to add a keyword override in front of the fields originating from the interfaces. The open api generator has no way of knowing which fields exist in the interfaces, so the fields names have to be provided via this vendor extension for the code to compile correctly. If x-kotlin-implements is missing on the schema definition, this extension is ignored entirely.

I implemented some basic tests - verified that my changes do not break the current way of handling inheritance and Serializable implementation. Also the java logic related to the implementation is in such a place that it should allow for a pretty easy implementation of the feature in the other kotlin code generators. I want to gather feedback whether this approach is acceptable. I decided against reusing x-implements as I can imagine the same swagger document being used in environments with mixed tech-stack, so I though that being able to implement different interfaces for java and kotlin might be useful. But I am ok with changing the extensions to x-implements and x-implements-fields if it increases the chance of having this merged into the codebase.

I could not find an issue ticket for exactly this issue, so I went ahead and created the PR without linking anything. I hope it is ok.

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.x.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR solves a reported issue, reference it using GitHub's linking syntax (e.g., having "fixes #123" present in the PR description)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request. - tagging: @dr4ke616 , @karismann , @Zomzog , @andrewemery , @4brunu , @yutaka0m , @stefankoppier , @e5l

@Picazsoo Picazsoo changed the title Feat/implement x implements for kotlin spring [kotlin-spring][server] Feat: Allow implementation of arbitrary interface in DTOs (similar to x-implements from java-spring) Sep 11, 2025
Comment on lines +20 to +21
){{/discriminator}}{{! no newline
}}{{#parent}} : {{{.}}}{{! no newline
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This misuse of comments to prevent line break might be controversial. However it seemed to improve the readability as otherwise the line would be very very long. But I can do one-liner if it is preferred to this.

Comment on lines 708 to 709
x-kotlin-implements: [ 'com.some.package.Named' ]
x-kotlin-implements-fields: [ name ]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the way the vendor extension is used - define the interface and then specify the actual fields that should have the override keyword prepended.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding a test spec (used in java unit tests)

can we also include a samples generated from this spec by adding a yaml config file under ./bin/config and add the new folder to the github workflow (.github/workflows/samples-kotlin-client.yaml) to ensure the output compiles without issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. I am on it. That definitely makes sense and I was wondering how the ability to compile is checked.

Copy link
Contributor Author

@Picazsoo Picazsoo Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I hope I did it correctly. It was definitely worthwhile as I uncovered a mistake in one of my template changes. I added the generated files (and manually added the interfaces the models must implement) and added the output folder to the samples-kotlin-client.yaml. Hope that is all that is needed for now - I guess the pipelines should now automatically pick it up for compilation?

* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
enum class {{classname}}(@get:JsonValue val value: {{dataType}}) {
enum class {{classname}}(@get:JsonValue val value: {{dataType}}) {{#vendorExtensions.x-kotlin-implements}}{{#-first}}: {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-kotlin-implements}}{
Copy link
Contributor Author

@Picazsoo Picazsoo Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think implementing the interface on enum is a bit useless as the only thing one can implement on generated enum is an interface with some default methods? Or correct me if I am wrong.

I did it here mostly to achieve parity with java x-implements.

@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just formatting changes - there are lot of those.

@wing328
Copy link
Member

wing328 commented Sep 12, 2025

Thanks for the PR but your commit (as shown in the Commits tab) is not linked to your Github account, which means this PR won't count as your contribution in https://github.com/OpenAPITools/openapi-generator/graphs/contributors.

Let me know if you need help fixing it.

Ref: https://github.com/OpenAPITools/openapi-generator/wiki/FAQ#how-can-i-update-commits-that-are-not-linked-to-my-github-account

Comment on lines 838 to 841
List<String> implementedInterfacesClasses = (List<String>) m.getVendorExtensions().getOrDefault(VendorExtension.X_KOTLIN_IMPLEMENTS.getName(), List.of());
List<String> implementedInterfacesFields = implementedInterfacesClasses.isEmpty()
? List.of()
: (List<String>) m.getVendorExtensions().getOrDefault(VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS.getName(), List.of());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to log some info or warn here if the x-kotlin-implements-field is defined on the model without corresponding x-kotlin-implements? To make it a bit more user-friendly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good to me. please add some log

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@Picazsoo Picazsoo force-pushed the feat/implement-x-implements-for-kotlin-spring branch from f61c542 to 7198cdd Compare September 15, 2025 08:03
@Picazsoo Picazsoo force-pushed the feat/implement-x-implements-for-kotlin-spring branch from c7ba56c to 3d78287 Compare September 15, 2025 08:37
@Picazsoo
Copy link
Contributor Author

I added the warn logs as well as more complex case of the arbitrary interface being extended by a schema with discriminator - hence generated interface extending the custom interface. Is anything more needed?

I also tried to fix the issue with the email in commits - hope I did it correctly.

… Pet.Status in implementations. This is a separate bug - not caused by x-kotlin-implements
@Picazsoo Picazsoo force-pushed the feat/implement-x-implements-for-kotlin-spring branch from 3da9b01 to 212d2cc Compare September 15, 2025 15:18
@Picazsoo
Copy link
Contributor Author

I removed the "status" enum from Pet definition as it fails to generate code that will compile. This is not caused by my changes - it is some already existing bug related to how inner enums are handled in inheritance.

@wing328
Copy link
Member

wing328 commented Sep 15, 2025

I removed the "status" enum from Pet definition as it fails to generate code that will compile.

👌

agreed we can look into that later with a separate pr to fix it

@wing328 wing328 merged commit 6278512 into OpenAPITools:master Sep 15, 2025
48 checks passed
Goopher pushed a commit to Goopher/openapi-generator that referenced this pull request Sep 16, 2025
…face in DTOs (similar to x-implements from java-spring) (OpenAPITools#21950)

* add basic implementation and tests

* improve test a bit

* modify kotlin-spring.md

* add x-kotlin-implements also to enum

* update samples & properly define implemented vendor extension

* use enum.getName() instead of hardcoded string as key in vendor extension map

* fix docs

* fix test openapi spec and test

* add samples for x-kotlin-implements

* add samples for x-kotlin-implements to proper output folder

* fix

* revert unwanted changes

* move to correct place

* fix mustache template

* add to samples-kotlin-server.yaml

* reuse 1 open api schema for everything. Add also case where interface extends interface.

* add warn logs when x-kotlin-implements-fields is used without x-kotlin-implements to improve usability

* remove unnecessary generated files

* remove unnecessary generated files

* remove "status" inner enum from Pet as it fails to properly import as Pet.Status in implementations. This is a separate bug - not caused by x-kotlin-implements
@wing328 wing328 added this to the 7.16.0 milestone Sep 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants