Repository navigation
feat(kotlin-spring): support generic ResponseEntity return types - #24805
c19yamamoto wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 9 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 9 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="modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-spring/apiDelegate.mustache:39">
P2: The return-type expression is now a single ~700-character line that embeds the sealed-interface/returnTypes logic twice (once in the `useResponseEntity` branch, once in `^useResponseEntity`), and the identical block is duplicated again in apiInterface.mustache. The `^useResponseEntity` and `^useGenericResponseEntity` cases are equivalent, so this large conditional expression is copy-pasted four times across the two templates. This is a real maintainability/DRY regression: any change to how the body type is resolved (e.g., a new response-type mode) must be made in four places, and the unreadable single-line Mustache makes divergence likely. Extract the shared sealed/returnTypes resolution into a dedicated partial (e.g. `returnTypesBody.mustache`) and reference it from both the `useGenericResponseEntity` and non-generic branches in both templates.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| {{/hasParams}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, | ||
| {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, | ||
| {{/includeHttpRequestContext}}{{/hasParams}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} { | ||
| {{/includeHttpRequestContext}}{{/hasParams}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}): {{#useResponseEntity}}ResponseEntity<{{#useGenericResponseEntity}}*{{/useGenericResponseEntity}}{{^useGenericResponseEntity}}{{#useSealedResponseInterfaces}}{{#vendorExtensions.x-sealed-response-interface}}{{vendorExtensions.x-sealed-response-interface}}{{/vendorExtensions.x-sealed-response-interface}}{{^vendorExtensions.x-sealed-response-interface}}{{>returnTypes}}{{/vendorExtensions.x-sealed-response-interface}}{{/useSealedResponseInterfaces}}{{^useSealedResponseInterfaces}}{{>returnTypes}}{{/useSealedResponseInterfaces}}{{/useGenericResponseEntity}}>{{/useResponseEntity}}{{^useResponseEntity}}{{#useSealedResponseInterfaces}}{{#vendorExtensions.x-sealed-response-interface}}{{vendorExtensions.x-sealed-response-interface}}{{/vendorExtensions.x-sealed-response-interface}}{{^vendorExtensions.x-sealed-response-interface}}{{>returnTypes}}{{/vendorExtensions.x-sealed-response-interface}}{{/useSealedResponseInterfaces}}{{^useSealedResponseInterfaces}}{{>returnTypes}}{{/useSealedResponseInterfaces}}{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} { |
There was a problem hiding this comment.
P2: The return-type expression is now a single ~700-character line that embeds the sealed-interface/returnTypes logic twice (once in the useResponseEntity branch, once in ^useResponseEntity), and the identical block is duplicated again in apiInterface.mustache. The ^useResponseEntity and ^useGenericResponseEntity cases are equivalent, so this large conditional expression is copy-pasted four times across the two templates. This is a real maintainability/DRY regression: any change to how the body type is resolved (e.g., a new response-type mode) must be made in four places, and the unreadable single-line Mustache makes divergence likely. Extract the shared sealed/returnTypes resolution into a dedicated partial (e.g. returnTypesBody.mustache) and reference it from both the useGenericResponseEntity and non-generic branches in both templates.
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-spring/apiDelegate.mustache, line 39:
<comment>The return-type expression is now a single ~700-character line that embeds the sealed-interface/returnTypes logic twice (once in the `useResponseEntity` branch, once in `^useResponseEntity`), and the identical block is duplicated again in apiInterface.mustache. The `^useResponseEntity` and `^useGenericResponseEntity` cases are equivalent, so this large conditional expression is copy-pasted four times across the two templates. This is a real maintainability/DRY regression: any change to how the body type is resolved (e.g., a new response-type mode) must be made in four places, and the unreadable single-line Mustache makes divergence likely. Extract the shared sealed/returnTypes resolution into a dedicated partial (e.g. `returnTypesBody.mustache`) and reference it from both the `useGenericResponseEntity` and non-generic branches in both templates.</comment>
<file context>
@@ -36,7 +36,7 @@ interface {{classname}}Delegate {
{{/hasParams}}{{#reactive}}exchange: org.springframework.web.server.ServerWebExchange{{/reactive}}{{^reactive}}request: {{javaxPackage}}.servlet.http.HttpServletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}},
- {{/includeHttpRequestContext}}{{/hasParams}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}): {{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} {
+ {{/includeHttpRequestContext}}{{/hasParams}}pageable: Pageable{{/vendorExtensions.x-spring-paginated}}): {{#useResponseEntity}}ResponseEntity<{{#useGenericResponseEntity}}*{{/useGenericResponseEntity}}{{^useGenericResponseEntity}}{{#useSealedResponseInterfaces}}{{#vendorExtensions.x-sealed-response-interface}}{{vendorExtensions.x-sealed-response-interface}}{{/vendorExtensions.x-sealed-response-interface}}{{^vendorExtensions.x-sealed-response-interface}}{{>returnTypes}}{{/vendorExtensions.x-sealed-response-interface}}{{/useSealedResponseInterfaces}}{{^useSealedResponseInterfaces}}{{>returnTypes}}{{/useSealedResponseInterfaces}}{{/useGenericResponseEntity}}>{{/useResponseEntity}}{{^useResponseEntity}}{{#useSealedResponseInterfaces}}{{#vendorExtensions.x-sealed-response-interface}}{{vendorExtensions.x-sealed-response-interface}}{{/vendorExtensions.x-sealed-response-interface}}{{^vendorExtensions.x-sealed-response-interface}}{{>returnTypes}}{{/vendorExtensions.x-sealed-response-interface}}{{/useSealedResponseInterfaces}}{{^useSealedResponseInterfaces}}{{>returnTypes}}{{/useSealedResponseInterfaces}}{{/useResponseEntity}}{{^skipDefaultDelegateInterface}} {
{{>methodBody}}{{! prevent indent}}
}{{/skipDefaultDelegateInterface}}
</file context>
Preserve both generic response entity modes and upstream pagination modes. Update the declarative HTTP interface test for upstream path-based API grouping. Co-authored-by: Codex <noreply@openai.com>
Operations returning an empty
201response or a202response with a body can currently generate an unusableResponseEntity<Unit>signature. This addsgenerateGenericResponseEntity=NEVER|ALWAYStokotlin-spring, withALWAYSgeneratingResponseEntity<*>.NEVER(default) preserves existing return types. The option has no effect whenuseResponseEntity=false. String modes allow future extensions; boolean aliases are not supported.Supports controllers, API interfaces, delegates, generated API tests, and declarative HTTP interfaces.
Fixes #24804.
Tests
./mvnw clean package: full project build and tests passed, including 292KotlinSpringServerCodegenTestcases../bin/generate-samples.sh ./bin/configs/*.yaml: all 800 sample configurations regenerated successfully, with no differences../bin/utils/export_docs_generators.sh: all generator documentation regenerated successfully, with no differences.ResponseEntity<*>withALWAYS, andResponseEntity<Unit>withNEVERfor the declarative HTTP interface.Kotlin technical committee: @karismann @Zomzog @andrewemery @4brunu @stefankoppier @e5l
PR checklist
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.