[kotlin][jvm-ktor] Fix query parameters typed as type:object (Map and model)#23763
Merged
wing328 merged 1 commit intoMay 12, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
1 issue found across 4 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-client/libraries/jvm-ktor/api.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-ktor/api.mustache:137">
P1: Model query params ignore `explode=false` and always serialize each property as its own query key.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
… model)
The query parameter block in jvm-ktor/api.mustache used a single
toMultiValue(...) call for every container type. Map<K,V> is not Iterable,
so any query parameter with schema `type: object, additionalProperties: ...`
failed to compile. Likewise, query parameters with `type: object, properties: ...`
compiled but emitted toString() of the generated data class into the URL
instead of OAS-defined serialization.
Split the queryParams block into three branches:
- isModel -> deepObject: per-field, key = paramBaseName[fieldBaseName]
form+explode=true: per-field, key = fieldBaseName
form+explode=false: single entry, CSV of "field,value" pairs
(non-null fields only) under baseName
- isMap -> deepObject: forEach with baseName[$key]
form+explode=true: forEach with bare $key
form+explode=false: joinToString(",") under baseName
- default -> unchanged (scalar/array path via toMultiValue or listOf)
KotlinClientCodegen now exposes the outer parameter's OAS baseName on each
generated field via the `x-kotlin-param-base-name` vendor extension. The
jvm-ktor template uses it to build correct deepObject URL keys for models,
since Mustache provides no access to the outer scope from inside {{#vars}}.
Added KotlinClientCodegenApiTest#testJvmKtorQueryParamWithTypeObject
covering the 9 (schema x style/explode) combinations.
No existing sample changed (verified via ./bin/generate-samples.sh on the
three jvm-ktor configs): the fix only activates new branches for previously
broken cases.
d3c4498 to
deeace1
Compare
Contributor
Author
|
@cubic-dev-ai Good catch — the
All 71 |
Member
|
Ran some tests locally and the result is good. Thanks for contributing the fix. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #23762
Summary
Reworks query parameter handling in the jvm-ktor template to correctly serialize
type: objectschemas, plus a smallKotlinClientCodegenchange so the template can build correct deepObject URLs for models.Three branches in
kotlin-client/libraries/jvm-ktor/api.mustache:isModelparamBaseName[fieldBaseName]fieldBaseNamefield,valuepairs (non-null fields only) underbaseNameisMapforEachwithbaseName[$key]forEachwith bare$keyjoinToString(",")of map entries underbaseNameBehavior after the fix
additionalProperties:)form/true?k1=v1&k2=v2form/false?param=k1,v1,k2,v2deepObject?param[k1]=v1¶m[k2]=v2properties:)form/true?field1=…&field2=…form/false?param=field1,value1,field2,value2deepObject?paramBaseName[field1]=…¶mBaseName[field2]=…Implementation notes
KotlinClientCodegennow exposes the outer parameter's OAS baseName on each generated field via thex-kotlin-param-base-namevendor extension. The jvm-ktor template uses it for the deepObject URL prefix on models, since Mustache provides no access to the outer scope from inside{{#vars}}.Note on parameter naming (snake_case vs camelCase)
For models with
style: deepObject, the URL prefix is the OASbaseName, not the Kotlin identifier. Example: a parameter declared asgenerates a Kotlin parameter named
modelDeep(camelCase), but the URL key remains?model_deep[a]=…per OAS. This is the role of the newx-kotlin-param-base-namevendor extension: it propagates the parameter'sbaseNameinto thevarsscope, which Mustache otherwise cannot reach.For comparison, the existing
jvm-okhttptemplate currently emits?modelDeep[a]=…(kotlin paramName) in the same scenario. This PR does not touchjvm-okhttp— scope is intentionally limited tojvm-ktor.Test plan
KotlinClientCodegenApiTest#testJvmKtorQueryParamWithTypeObjectcovering the 6 affected (schema × style/explode) combinations plus a regression assertion that the old brokenmapDeep?.apply {shape is gone.KotlinClient*Testcases pass../bin/generate-samples.sh ./bin/configs/kotlin-jvm-ktor-{gson,jackson,kotlinx_serialization}.yaml— no existing sample changed, the fix only activates new branches for previously broken cases.MockEngineproduces the URLs in the table above for all 6 cases.