From 58b99b653aeefc7eb513aa9cd8c6f22cdcc8bfdd Mon Sep 17 00:00:00 2001 From: Wiebren Braakman Date: Tue, 8 Sep 2026 10:18:12 +0200 Subject: [PATCH] [rust] fix: map-typed query parameters called .to_string() on a HashMap HashMap implements neither Display nor ToString, so the generated client did not compile (E0599) wherever a map-typed query parameter fell through to the scalar path: a required non-nullable map in both reqwest and reqwest-trait, and the nullable/optional non-deepObject fallthroughs in reqwest-trait. Serialize the map as one json-encoded parameter with serde_json::to_string, exactly how reqwest's optional branch already handles non-primitive parameters. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GcwZ1arjLZNpetHz2a3TJz --- .../resources/rust/reqwest-trait/api.mustache | 17 ++++++++++++ .../main/resources/rust/reqwest/api.mustache | 5 ++++ .../codegen/rust/RustClientCodegenTest.java | 26 +++++++++++++++++++ .../resources/3_0/rust/map-query-params.yaml | 25 ++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 modules/openapi-generator/src/test/resources/3_0/rust/map-query-params.yaml diff --git a/modules/openapi-generator/src/main/resources/rust/reqwest-trait/api.mustache b/modules/openapi-generator/src/main/resources/rust/reqwest-trait/api.mustache index cf16c0fc24b2..56d0a7685f87 100644 --- a/modules/openapi-generator/src/main/resources/rust/reqwest-trait/api.mustache +++ b/modules/openapi-generator/src/main/resources/rust/reqwest-trait/api.mustache @@ -188,7 +188,12 @@ impl {{classname}} for {{classname}}Client { {{/isArray}} {{^isArray}} {{^isNullable}} + {{#isMap}} + local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(&{{{paramName}}})?)]); + {{/isMap}} + {{^isMap}} local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &{{{paramName}}}.to_string())]); + {{/isMap}} {{/isNullable}} {{#isNullable}} {{#isDeepObject}} @@ -228,9 +233,16 @@ impl {{classname}} for {{classname}}Client { {{/isModel}} {{^isObject}} {{^isModel}} + {{#isMap}} + if let Some(ref param_value) = {{{paramName}}} { + local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(param_value)?)]); + }; + {{/isMap}} + {{^isMap}} if let Some(ref param_value) = {{{paramName}}} { local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", ¶m_value.to_string())]); }; + {{/isMap}} {{/isModel}} {{/isObject}} {{/isDeepObject}} @@ -273,7 +285,12 @@ impl {{classname}} for {{classname}}Client { {{/isModel}} {{^isObject}} {{^isModel}} + {{#isMap}} + local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(param_value)?)]); + {{/isMap}} + {{^isMap}} local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", ¶m_value.to_string())]); + {{/isMap}} {{/isModel}} {{/isObject}} {{/isDeepObject}} diff --git a/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache b/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache index 5224b0c4d9b5..d843af0dac97 100644 --- a/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache +++ b/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache @@ -166,7 +166,12 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: {{/isArray}} {{^isArray}} {{^isNullable}} + {{#isMap}} + req_builder = req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(&{{{vendorExtensions.x-rust-param-identifier}}})?)]); + {{/isMap}} + {{^isMap}} req_builder = req_builder.query(&[("{{{baseName}}}", &{{{vendorExtensions.x-rust-param-identifier}}}.to_string())]); + {{/isMap}} {{/isNullable}} {{#isNullable}} {{#isDeepObject}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java index d4bc7c1845ec..de9427aafdbe 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java @@ -293,6 +293,32 @@ public void testIntegerPropertyEnum() throws IOException { TestUtils.assertFileNotContains(outputPath, linearize("#[serde(rename = \"0\")]")); } + @Test + public void testMapQueryParamsSerializeAsJson() throws IOException { + // HashMap implements neither Display nor ToString, so the .to_string() the templates + // emitted for a map-typed query parameter did not compile (E0599) - for a required map + // in both libraries, and for optional/nullable maps in reqwest-trait too + for (String library : new String[] {"reqwest", "reqwest-trait"}) { + Path target = Files.createTempDirectory("test"); + target.toFile().deleteOnExit(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("rust") + .setLibrary(library) + .setInputSpec("src/test/resources/3_0/rust/map-query-params.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString().replace("\\", "/")); + new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + Path outputPath = Path.of(target.toString(), "/src/apis/default_api.rs"); + TestUtils.assertFileExists(outputPath); + // the required and the optional map both serialize as one json-encoded parameter, + // like the other libraries' non-primitive parameters + TestUtils.assertFileContains(outputPath, "serde_json::to_string(&"); + TestUtils.assertFileContains(outputPath, "(\"counts\", &serde_json::to_string(param_value)?)"); + TestUtils.assertFileNotContains(outputPath, "labels.to_string()"); + TestUtils.assertFileNotContains(outputPath, "param_value.to_string()"); + } + } + @Test public void testArrayWithObjectEnumValues() throws IOException { Path target = Files.createTempDirectory("test"); diff --git a/modules/openapi-generator/src/test/resources/3_0/rust/map-query-params.yaml b/modules/openapi-generator/src/test/resources/3_0/rust/map-query-params.yaml new file mode 100644 index 000000000000..804b62d63775 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/rust/map-query-params.yaml @@ -0,0 +1,25 @@ +openapi: 3.0.3 +info: + title: map query params + version: 1.0.0 +paths: + /items: + get: + operationId: listItems + parameters: + - name: labels + in: query + required: true + schema: + type: object + additionalProperties: + type: string + - name: counts + in: query + schema: + type: object + additionalProperties: + type: integer + responses: + '200': + description: ok