Skip to content

Commit

Permalink
[BUG][java][resttemplate] Fix NPE when query param with value null is…
Browse files Browse the repository at this point in the history
… exploded (#17568)

* Fix NPE when query param with value null is exploded

* Polish

* Add test

* Update tests

* Add integration test
  • Loading branch information
jorgerod authored Jan 10, 2024
1 parent d0e533d commit 61c4047
Show file tree
Hide file tree
Showing 17 changed files with 150 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,12 @@ public class {{classname}} {
final MultiValueMap<String, String> localVarCookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();{{#hasQueryParams}}

{{#queryParams}}{{#isExplode}}{{#hasVars}}{{#vars}} localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}.{{getter}}()));
{{/vars}}{{/hasVars}}{{^hasVars}} localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}));
{{/hasVars}}{{/isExplode}}{{^isExplode}} localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}));
{{/isExplode}}{{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}
{{#queryParams}}{{#isExplode}}{{#hasVars}}
if ({{paramName}} != null) {
{{#vars}} localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}.{{getter}}()));
{{/vars}}}{{/hasVars}}{{^hasVars}}localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}));
{{/hasVars}}{{/isExplode}}{{^isExplode}}localVarQueryParams.putAll(apiClient.parameterToMultiValueMap({{#collectionFormat}}ApiClient.CollectionFormat.valueOf("{{{.}}}".toUpperCase(Locale.ROOT)){{/collectionFormat}}{{^collectionFormat}}null{{/collectionFormat}}, "{{baseName}}", {{paramName}}));
{{/isExplode}}{{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}

{{#headerParams}}if ({{paramName}} != null)
localVarHeaderParams.add("{{baseName}}", apiClient.parameterToString({{paramName}}));{{^-last}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2938,4 +2938,32 @@ private void testHandleURIEnum(String library, String[] expectedInnerEnumLines,
assertNotNull(apiFile);
JavaFileAssert.assertThat(apiFile).fileContains(expectedInnerEnumLines);
}

@Test
public void testQueryParamsExploded_whenQueryParamIsNull() throws IOException {

Map<String, Object> properties = new HashMap<>();
properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api");

File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("java")
.setLibrary(JavaClientCodegen.RESTTEMPLATE)
.setAdditionalProperties(properties)
.setInputSpec("src/test/resources/3_0/issue_17555.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));


DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);

validateJavaSourceFiles(files);


Path petApi = Paths.get(output + "/src/main/java/xyz/abcdef/api/DepartmentApi.java");
TestUtils.assertFileContains(petApi, "if (filter != null) {");
}
}
51 changes: 51 additions & 0 deletions modules/openapi-generator/src/test/resources/3_0/issue_17555.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
openapi: 3.0.0
info:
description: My description
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: department
description: Everything about your Department
paths:
/api/department/{departmentId}/teams:
get:
tags:
- Department
summary: Find Department Teams
operationId: findDepartmentTeams
description: Find Department Teams
parameters:
- $ref: '#/components/parameters/departmentIdParam'
- $ref: '#/components/parameters/teamQueryParam'
responses:
'200':
description: OK
components:
schemas:
TeamCriteriaDTO:
type: object
title: TeamCriteriaDTO
properties:
key:
type: string
name:
type: string
parameters:
departmentIdParam:
name: departmentId
in: path
description: ID of the department to search
required: true
schema:
type: string
teamQueryParam:
name: filter
in: query
description: Fetch teams query
required: false
allowEmptyValue: true
schema:
$ref: '#/components/schemas/TeamCriteriaDTO'
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public ResponseEntity<String> testEnumRefStringWithHttpInfo(String enumNonrefStr

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "enum_nonref_string_query", enumNonrefStringQuery));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "enum_ref_string_query", enumRefStringQuery));


final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -134,7 +134,7 @@ public ResponseEntity<String> testQueryDatetimeDateStringWithHttpInfo(OffsetDate
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "datetime_query", datetimeQuery));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "date_query", dateQuery));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "string_query", stringQuery));


final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -184,7 +184,7 @@ public ResponseEntity<String> testQueryIntegerBooleanStringWithHttpInfo(Integer
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "integer_query", integerQuery));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "boolean_query", booleanQuery));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "string_query", stringQuery));


final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -227,13 +227,15 @@ public ResponseEntity<String> testQueryStyleDeepObjectExplodeTrueObjectWithHttpI
final MultiValueMap<String, String> localVarCookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus()));


if (queryObject != null) {
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus()));
}

final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -277,7 +279,7 @@ public ResponseEntity<String> testQueryStyleDeepObjectExplodeTrueObjectAllOfWith
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "query_object", queryObject));


final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -320,8 +322,10 @@ public ResponseEntity<String> testQueryStyleFormExplodeTrueArrayStringWithHttpIn
final MultiValueMap<String, String> localVarCookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "values", queryObject.getValues()));


if (queryObject != null) {
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "values", queryObject.getValues()));
}

final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -364,13 +368,15 @@ public ResponseEntity<String> testQueryStyleFormExplodeTrueObjectWithHttpInfo(Pe
final MultiValueMap<String, String> localVarCookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus()));


if (queryObject != null) {
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "id", queryObject.getId()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "name", queryObject.getName()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "category", queryObject.getCategory()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "photoUrls", queryObject.getPhotoUrls()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "tags", queryObject.getTags()));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "status", queryObject.getStatus()));
}

final String[] localVarAccepts = {
"text/plain"
Expand Down Expand Up @@ -414,7 +420,7 @@ public ResponseEntity<String> testQueryStyleFormExplodeTrueObjectAllOfWithHttpIn
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "query_object", queryObject));


final String[] localVarAccepts = {
"text/plain"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
package org.openapitools.client;

import org.junit.Assert;
import org.openapitools.client.api.*;
import org.openapitools.client.model.*;
import org.junit.Test;
import org.junit.Ignore;
import org.openapitools.client.api.BodyApi;
import org.openapitools.client.api.QueryApi;
import org.openapitools.client.model.Category;
import org.openapitools.client.model.Pet;

import java.io.IOException;
import java.util.*;
import java.util.Arrays;

import static org.junit.Assert.assertNotNull;


/**
Expand All @@ -43,12 +45,17 @@ public void testEchoBodyPet() {
photoUrls(Arrays.asList(new String[]{"http://a.com", "http://b.com"})).category(new Category().id(987L).name("new category"));

Pet p = bodyApi.testEchoBodyPet(pet);
Assert.assertNotNull(p);
assertNotNull(p);
Assert.assertEquals("Hello World", p.getName());
Assert.assertEquals(Long.valueOf(12345L), p.getId());

// response is empty body
Pet p2 = bodyApi.testEchoBodyPet(null);
Assert.assertNull(p2);
}

@Test
public void testQueryParamsExploded_whenQueryParamIsNull() {
assertNotNull(api.testQueryStyleFormExplodeTrueObject(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public ResponseEntity<List<Pet>> findPetsByStatusWithHttpInfo(List<String> statu
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "status", status));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down Expand Up @@ -240,7 +240,7 @@ public ResponseEntity<List<Pet>> findPetsByTagsWithHttpInfo(List<String> tags) t
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "tags", tags));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public ResponseEntity<String> loginUserWithHttpInfo(String username, String pass

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "username", username));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "password", password));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public ResponseEntity<List<Pet>> findPetsByStatusWithHttpInfo(List<String> statu
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "status", status));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down Expand Up @@ -240,7 +240,7 @@ public ResponseEntity<List<Pet>> findPetsByTagsWithHttpInfo(List<String> tags) t
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "tags", tags));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public ResponseEntity<String> loginUserWithHttpInfo(String username, String pass

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "username", username));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "password", password));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public ResponseEntity<List<Pet>> findPetsByStatusWithHttpInfo(List<String> statu
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "status", status));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down Expand Up @@ -240,7 +240,7 @@ public ResponseEntity<List<Pet>> findPetsByTagsWithHttpInfo(List<String> tags) t
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("csv".toUpperCase(Locale.ROOT)), "tags", tags));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public ResponseEntity<String> loginUserWithHttpInfo(String username, String pass

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "username", username));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "password", password));


final String[] localVarAccepts = {
"application/xml", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public ResponseEntity<Void> fakeHttpSignatureTestWithHttpInfo(Pet pet, String qu
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "query_1", query1));


if (header1 != null)
localVarHeaderParams.add("header_1", apiClient.parameterToString(header1));
Expand Down Expand Up @@ -588,7 +588,7 @@ public ResponseEntity<Void> testBodyWithQueryParamsWithHttpInfo(String query, Us
final MultiValueMap<String, Object> localVarFormParams = new LinkedMultiValueMap<String, Object>();

localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "query", query));


final String[] localVarAccepts = { };
final List<MediaType> localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
Expand Down Expand Up @@ -818,7 +818,7 @@ public ResponseEntity<Void> testEnumParametersWithHttpInfo(List<String> enumHead
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "enum_query_integer", enumQueryInteger));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "enum_query_double", enumQueryDouble));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("multi".toUpperCase(Locale.ROOT)), "enum_query_model_array", enumQueryModelArray));


if (enumHeaderStringArray != null)
localVarHeaderParams.add("enum_header_string_array", apiClient.parameterToString(enumHeaderStringArray));
Expand Down Expand Up @@ -899,7 +899,7 @@ public ResponseEntity<Void> testGroupParametersWithHttpInfo(Integer requiredStri
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "required_int64_group", requiredInt64Group));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "string_group", stringGroup));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "int64_group", int64Group));


if (requiredBooleanGroup != null)
localVarHeaderParams.add("required_boolean_group", apiClient.parameterToString(requiredBooleanGroup));
Expand Down Expand Up @@ -1185,7 +1185,7 @@ public ResponseEntity<Void> testQueryParameterCollectionFormatWithHttpInfo(List<
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(ApiClient.CollectionFormat.valueOf("multi".toUpperCase(Locale.ROOT)), "context", context));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "language", language));
localVarQueryParams.putAll(apiClient.parameterToMultiValueMap(null, "allowEmpty", allowEmpty));


final String[] localVarAccepts = { };
final List<MediaType> localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
Expand Down
Loading

0 comments on commit 61c4047

Please sign in to comment.