From 8f927df6421943d8bd612a78ed8efe9ab166f1ca Mon Sep 17 00:00:00 2001 From: Jorge Date: Thu, 9 Apr 2026 16:21:05 +0200 Subject: [PATCH] fix: handle null query parameters in REST client --- .../Java/libraries/restclient/api.mustache | 4 ++- .../codegen/java/JavaClientCodegenTest.java | 16 ++++++++++ .../org/openapitools/client/api/QueryApi.java | 32 +++++++++++-------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/restclient/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/restclient/api.mustache index 91c106b48d6b..48f7beb1ea4b 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/restclient/api.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/restclient/api.mustache @@ -115,9 +115,11 @@ public class {{classname}} { {{^queryIsJsonMimeType}} {{#isExplode}} {{#hasVars}} + if ({{paramName}} != null) { {{#vars}} - queryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}.{{getter}}())); + queryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}.{{getter}}())); {{/vars}} + } {{/hasVars}} {{^hasVars}} queryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}})); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 5935b2e61aa0..8b8a497d4074 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -2642,6 +2642,22 @@ public void testQueryParamsExploded_whenQueryParamIsNull() { assertFileContains(output.resolve("src/main/java/xyz/abcdef/api/DepartmentApi.java"), "if (filter != null) {"); } + @Test + public void testQueryParamsExploded_whenQueryParamIsNull_restclient() { + final Path output = newTempFolder(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(JAVA_GENERATOR) + .setLibrary(JavaClientCodegen.RESTCLIENT) + .setAdditionalProperties(Map.of(CodegenConstants.API_PACKAGE, "xyz.abcdef.api")) + .setInputSpec("src/test/resources/3_0/issue_17555.yaml") + .setOutputDir(output.toString().replace("\\", "/")); + + List files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + + validateJavaSourceFiles(files); + assertFileContains(output.resolve("src/main/java/xyz/abcdef/api/DepartmentApi.java"), "if (filter != null) {"); + } + @Test public void generateAllArgsConstructor() { Map files = generateFromContract("src/test/resources/3_0/java/all_args_constructor.yaml", JavaClientCodegen.RESTTEMPLATE, diff --git a/samples/client/echo_api/java/restclient/src/main/java/org/openapitools/client/api/QueryApi.java b/samples/client/echo_api/java/restclient/src/main/java/org/openapitools/client/api/QueryApi.java index ff8744f47a76..149d9e7ab45c 100644 --- a/samples/client/echo_api/java/restclient/src/main/java/org/openapitools/client/api/QueryApi.java +++ b/samples/client/echo_api/java/restclient/src/main/java/org/openapitools/client/api/QueryApi.java @@ -306,12 +306,14 @@ private ResponseSpec testQueryStyleDeepObjectExplodeTrueObjectRequestCreation(@j final MultiValueMap cookieParams = new LinkedMultiValueMap<>(); final MultiValueMap formParams = new LinkedMultiValueMap<>(); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus())); + if (queryObject != null) { + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus())); + } final String[] localVarAccepts = { "text/plain" @@ -595,7 +597,9 @@ private ResponseSpec testQueryStyleFormExplodeTrueArrayStringRequestCreation(@ja final MultiValueMap cookieParams = new LinkedMultiValueMap<>(); final MultiValueMap formParams = new LinkedMultiValueMap<>(); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "values", queryObject.getValues())); + if (queryObject != null) { + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "values", queryObject.getValues())); + } final String[] localVarAccepts = { "text/plain" @@ -666,12 +670,14 @@ private ResponseSpec testQueryStyleFormExplodeTrueObjectRequestCreation(@jakarta final MultiValueMap cookieParams = new LinkedMultiValueMap<>(); final MultiValueMap formParams = new LinkedMultiValueMap<>(); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags())); - queryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus())); + if (queryObject != null) { + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags())); + queryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus())); + } final String[] localVarAccepts = { "text/plain"