From fc37be66027844bf5a5ca021f6ba173c2e9742a2 Mon Sep 17 00:00:00 2001 From: Wiebren Braakman Date: Fri, 4 Sep 2026 16:38:53 +0200 Subject: [PATCH 1/4] fix: [rust] type free-form object parameters as serde_json::Value, not models::serde_json::Value A free-form object parameter (type: object with no properties) maps to serde_json::Value, but the api templates qualify every non-primitive, non-container parameter type with models:: - and models re-exports no serde_json, so the generated crate fails with E0433. Free-form body parameters already avoid this because updateRequestBodyForObject marks them primitive; give non-body free-form parameters the same treatment. Free-form schemas with additionalProperties stay containers (HashMap) and keep their JSON serialization. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CxDNCjqJycKTfzVWg2SeTJ --- .../codegen/languages/RustClientCodegen.java | 10 ++++++ .../codegen/rust/RustClientCodegenTest.java | 24 +++++++++++++ .../rust/free-form-object-query-param.yaml | 36 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 modules/openapi-generator/src/test/resources/3_0/rust/free-form-object-query-param.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java index 3c70fb2b73b2..fc9003e2ab47 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java @@ -783,6 +783,16 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List 0) { 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..c919793dc5f6 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,30 @@ public void testIntegerPropertyEnum() throws IOException { TestUtils.assertFileNotContains(outputPath, linearize("#[serde(rename = \"0\")]")); } + @Test + public void testFreeFormObjectQueryParam() throws IOException { + Path target = Files.createTempDirectory("test"); + target.toFile().deleteOnExit(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("rust") + .setInputSpec("src/test/resources/3_0/rust/free-form-object-query-param.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString().replace("\\", "/")); + List files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + Path outputPath = Path.of(target.toString(), "/src/apis/default_api.rs"); + TestUtils.assertFileExists(outputPath); + // A free-form object query parameter maps to `serde_json::Value`, which lives + // outside of the `models` module. + TestUtils.assertFileContains(outputPath, "filter: Option"); + TestUtils.assertFileNotContains(outputPath, "models::serde_json"); + // A free-form object with additionalProperties stays a map. + TestUtils.assertFileContains(outputPath, "tags: Option>"); + TestUtils.assertFileContains(outputPath, "meta: Option>"); + // Maps keep their JSON serialization (`HashMap` does not implement `Display`). + TestUtils.assertFileContains(outputPath, "req_builder.query(&[(\"meta\", &serde_json::to_string(param_value)?)])"); + } + @Test public void testArrayWithObjectEnumValues() throws IOException { Path target = Files.createTempDirectory("test"); diff --git a/modules/openapi-generator/src/test/resources/3_0/rust/free-form-object-query-param.yaml b/modules/openapi-generator/src/test/resources/3_0/rust/free-form-object-query-param.yaml new file mode 100644 index 000000000000..789d2f46e94e --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/rust/free-form-object-query-param.yaml @@ -0,0 +1,36 @@ +openapi: 3.0.0 +info: + title: Free-form object query parameter + version: 1.0.0 +paths: + /things: + get: + operationId: listThings + parameters: + - name: filter + in: query + description: A free-form object query parameter. + schema: + type: object + - name: tags + in: query + description: A free-form object with typed additionalProperties (a map). + schema: + type: object + additionalProperties: + type: string + - name: meta + in: query + description: A free-form object with additionalProperties true (also a map). + schema: + type: object + additionalProperties: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + type: string From 1a9f8757398846d62802ea7711e8c7264145c37e Mon Sep 17 00:00:00 2001 From: Wiebren Braakman Date: Fri, 4 Sep 2026 20:38:26 +0200 Subject: [PATCH 2/4] ci: retrigger after ubuntu mirror outage From 4c6d8207b12b75f5d30c02b183e1a195c9abf19b Mon Sep 17 00:00:00 2001 From: Wiebren Braakman Date: Wed, 23 Sep 2026 09:18:05 +0200 Subject: [PATCH 3/4] [rust] tidy: shorten the free-form parameter comment Co-Authored-By: Claude Opus 5.5 (1M context) --- .../codegen/languages/RustClientCodegen.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java index fc9003e2ab47..00f882c3840e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java @@ -784,12 +784,9 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List Date: Wed, 23 Sep 2026 11:40:47 +0200 Subject: [PATCH 4/4] [rust] test: cover free-form object parameters in all four libraries Co-Authored-By: Claude Opus 5.5 (1M context) --- .../codegen/rust/RustClientCodegenTest.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) 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 c919793dc5f6..a2374ac452a4 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 @@ -295,26 +295,31 @@ public void testIntegerPropertyEnum() throws IOException { @Test public void testFreeFormObjectQueryParam() throws IOException { - Path target = Files.createTempDirectory("test"); - target.toFile().deleteOnExit(); - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("rust") - .setInputSpec("src/test/resources/3_0/rust/free-form-object-query-param.yaml") - .setSkipOverwrite(false) - .setOutputDir(target.toAbsolutePath().toString().replace("\\", "/")); - List files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); - files.forEach(File::deleteOnExit); - Path outputPath = Path.of(target.toString(), "/src/apis/default_api.rs"); - TestUtils.assertFileExists(outputPath); - // A free-form object query parameter maps to `serde_json::Value`, which lives - // outside of the `models` module. - TestUtils.assertFileContains(outputPath, "filter: Option"); - TestUtils.assertFileNotContains(outputPath, "models::serde_json"); - // A free-form object with additionalProperties stays a map. - TestUtils.assertFileContains(outputPath, "tags: Option>"); - TestUtils.assertFileContains(outputPath, "meta: Option>"); - // Maps keep their JSON serialization (`HashMap` does not implement `Display`). - TestUtils.assertFileContains(outputPath, "req_builder.query(&[(\"meta\", &serde_json::to_string(param_value)?)])"); + for (String library : List.of("reqwest", "hyper", "hyper0x", "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/free-form-object-query-param.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString().replace("\\", "/")); + List files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + Path outputPath = Path.of(target.toString(), "/src/apis/default_api.rs"); + TestUtils.assertFileExists(outputPath); + // A free-form object query parameter maps to `serde_json::Value`, which lives + // outside of the `models` module. + TestUtils.assertFileContains(outputPath, "filter: Option"); + TestUtils.assertFileNotContains(outputPath, "models::serde_json"); + // A free-form object with additionalProperties stays a map. + TestUtils.assertFileContains(outputPath, "tags: Option>"); + TestUtils.assertFileContains(outputPath, "meta: Option>"); + if (library.equals("reqwest")) { + // Maps keep their JSON serialization (`HashMap` does not implement `Display`). + TestUtils.assertFileContains(outputPath, "req_builder.query(&[(\"meta\", &serde_json::to_string(param_value)?)])"); + } + } } @Test