Skip to content

Commit 2d73a4d

Browse files
authored
Explode query params for kotlin generator (#13154)
1 parent 1fbc047 commit 2d73a4d

File tree

6 files changed

+75
-28
lines changed

6 files changed

+75
-28
lines changed

modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-retrofit2/api.mustache

+1-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ interface {{classname}} {
6060
* {{notes}}
6161
* Responses:{{#responses}}
6262
* - {{code}}: {{{message}}}{{/responses}}
63-
*
64-
{{#allParams}}
65-
* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}
66-
{{/allParams}}
63+
*{{>paramJavadoc}}
6764
* @return {{^useCoroutines}}[Call]<{{/useCoroutines}}{{#isResponseFile}}[ResponseBody]{{/isResponseFile}}{{^isResponseFile}}{{#returnType}}[{{{.}}}]{{/returnType}}{{^returnType}}[Unit]{{/returnType}}{{/isResponseFile}}{{^useCoroutines}}>{{/useCoroutines}}
6865
*/
6966
{{#isDeprecated}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@Query("{{baseName}}") {{{baseName}}}: {{#collectionFormat}}{{#isCollectionFormatMulti}}{{{dataType}}}{{/isCollectionFormatMulti}}{{^isCollectionFormatMulti}}{{{collectionFormat.toUpperCase}}}Params{{/isCollectionFormatMulti}}{{/collectionFormat}}{{^collectionFormat}}{{{dataType}}}{{/collectionFormat}}{{#required}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/required}}{{^required}}?{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{#allParams}}{{#isDeepObject}}
2+
* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}{{/isDeepObject}}{{^isDeepObject}}{{#isExplode}}{{#hasVars}}{{#vars}}
3+
* @param {{{baseName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}{{/vars}}{{/hasVars}}{{^hasVars}}
4+
* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}{{/hasVars}}{{/isExplode}}{{^isExplode}}
5+
* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}{{/isExplode}}{{/isDeepObject}}{{/allParams}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@Query("{{baseName}}") {{{paramName}}}: {{#collectionFormat}}{{#isCollectionFormatMulti}}{{{dataType}}}{{/isCollectionFormatMulti}}{{^isCollectionFormatMulti}}{{{collectionFormat.toUpperCase}}}Params{{/isCollectionFormatMulti}}{{/collectionFormat}}{{^collectionFormat}}{{{dataType}}}{{/collectionFormat}}{{#required}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/required}}{{^required}}?{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isQueryParam}}@Query("{{baseName}}") {{{paramName}}}: {{#collectionFormat}}{{#isCollectionFormatMulti}}{{{dataType}}}{{/isCollectionFormatMulti}}{{^isCollectionFormatMulti}}{{{collectionFormat.toUpperCase}}}Params{{/isCollectionFormatMulti}}{{/collectionFormat}}{{^collectionFormat}}{{{dataType}}}{{/collectionFormat}}{{#required}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/required}}{{^required}}?{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}{{/isQueryParam}}
1+
{{#isQueryParam}}{{#isDeepObject}}{{>queryParam}}{{/isDeepObject}}{{^isDeepObject}}{{#isExplode}}{{#hasVars}}{{#vars}}{{>explodedQueryParam}}{{^-last}}, {{/-last}}{{/vars}}{{/hasVars}}{{^hasVars}}{{>queryParam}}{{/hasVars}}{{/isExplode}}{{^isExplode}}{{>queryParam}}{{/isExplode}}{{/isDeepObject}}{{/isQueryParam}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java

+66-23
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,66 @@
1818
package org.openapitools.codegen.kotlin;
1919

2020
import io.swagger.v3.oas.models.OpenAPI;
21-
import io.swagger.v3.oas.models.media.*;
21+
import io.swagger.v3.oas.models.media.ArraySchema;
22+
import io.swagger.v3.oas.models.media.DateTimeSchema;
23+
import io.swagger.v3.oas.models.media.IntegerSchema;
24+
import io.swagger.v3.oas.models.media.MapSchema;
25+
import io.swagger.v3.oas.models.media.ObjectSchema;
26+
import io.swagger.v3.oas.models.media.Schema;
27+
import io.swagger.v3.oas.models.media.StringSchema;
28+
import org.openapitools.codegen.ClientOptInput;
29+
import org.openapitools.codegen.CodegenConstants;
2230
import org.openapitools.codegen.CodegenModel;
2331
import org.openapitools.codegen.CodegenProperty;
2432
import org.openapitools.codegen.DefaultCodegen;
33+
import org.openapitools.codegen.DefaultGenerator;
2534
import org.openapitools.codegen.TestUtils;
35+
import org.openapitools.codegen.config.CodegenConfigurator;
2636
import org.openapitools.codegen.languages.KotlinClientCodegen;
2737
import org.testng.Assert;
2838
import org.testng.annotations.DataProvider;
2939
import org.testng.annotations.Test;
3040

41+
import java.io.File;
42+
import java.io.IOException;
43+
import java.nio.file.Files;
44+
import java.nio.file.Paths;
45+
import java.util.HashMap;
46+
import java.util.List;
47+
import java.util.Map;
48+
3149
@SuppressWarnings("static-method")
3250
public class KotlinClientCodegenModelTest {
3351

3452
private Schema getArrayTestSchema() {
3553
return new ObjectSchema()
36-
.description("a sample model")
37-
.addProperties("id", new IntegerSchema().format("int64"))
38-
.addProperties("examples", new ArraySchema().items(new StringSchema()))
39-
.addRequiredItem("id");
54+
.description("a sample model")
55+
.addProperties("id", new IntegerSchema().format("int64"))
56+
.addProperties("examples", new ArraySchema().items(new StringSchema()))
57+
.addRequiredItem("id");
4058
}
4159

4260
private Schema getSimpleSchema() {
4361
return new ObjectSchema()
44-
.description("a sample model")
45-
.addProperties("id", new IntegerSchema().format("int64"))
46-
.addProperties("name", new StringSchema())
47-
.addProperties("createdAt", new DateTimeSchema())
48-
.addRequiredItem("id")
49-
.addRequiredItem("name");
62+
.description("a sample model")
63+
.addProperties("id", new IntegerSchema().format("int64"))
64+
.addProperties("name", new StringSchema())
65+
.addProperties("createdAt", new DateTimeSchema())
66+
.addRequiredItem("id")
67+
.addRequiredItem("name");
5068
}
5169

5270
private Schema getMapSchema() {
5371
return new ObjectSchema()
54-
.description("a sample model")
55-
.addProperties("mapping", new MapSchema()
56-
.additionalProperties(new StringSchema()));
72+
.description("a sample model")
73+
.addProperties("mapping", new MapSchema()
74+
.additionalProperties(new StringSchema()));
5775
}
5876

5977
private Schema getComplexSchema() {
6078
return new ObjectSchema()
61-
.description("a sample model")
62-
.addProperties("child", new ObjectSchema().$ref("#/components/schemas/Child"));
79+
.description("a sample model")
80+
.addProperties("child", new ObjectSchema().$ref("#/components/schemas/Child"));
6381
}
6482

6583
@Test(description = "convert a simple model")
@@ -321,11 +339,11 @@ public void complexPropertyTest() {
321339
@DataProvider(name = "modelNames")
322340
public static Object[][] modelNames() {
323341
return new Object[][]{
324-
{"TestNs.TestClass", new ModelNameTest("TestNs.TestClass", "TestNsTestClass")},
325-
{"$", new ModelNameTest("$", "Dollar")},
326-
{"for", new ModelNameTest("`for`", "For")},
327-
{"One<Two", new ModelNameTest("One<Two", "OneLessThanTwo")},
328-
{"this is a test", new ModelNameTest("this is a test", "ThisIsATest")}
342+
{"TestNs.TestClass", new ModelNameTest("TestNs.TestClass", "TestNsTestClass")},
343+
{"$", new ModelNameTest("$", "Dollar")},
344+
{"for", new ModelNameTest("`for`", "For")},
345+
{"One<Two", new ModelNameTest("One<Two", "OneLessThanTwo")},
346+
{"this is a test", new ModelNameTest("this is a test", "ThisIsATest")}
329347
};
330348
}
331349

@@ -341,9 +359,34 @@ public void sanitizeModelNames(final String name, final ModelNameTest testCase)
341359
Assert.assertEquals(cm.classname, testCase.expectedClassName);
342360
}
343361

362+
@Test
363+
public void testNativeClientExplodedQueryParamObject() throws IOException {
364+
Map<String, Object> properties = new HashMap<>();
365+
properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api");
366+
367+
File output = Files.createTempDirectory("test").toFile();
368+
output.deleteOnExit();
369+
370+
final CodegenConfigurator configurator = new CodegenConfigurator()
371+
.setGeneratorName("kotlin")
372+
.setLibrary("jvm-retrofit2")
373+
.setAdditionalProperties(properties)
374+
.setInputSpec("src/test/resources/3_0/issue4808.yaml")
375+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
376+
377+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
378+
DefaultGenerator generator = new DefaultGenerator();
379+
List<File> files = generator.opts(clientOptInput).generate();
380+
381+
Assert.assertEquals(files.size(), 28);
382+
TestUtils.assertFileContains(Paths.get(output + "/src/main/kotlin/xyz/abcdef/api/DefaultApi.kt"),
383+
"fun getSomeValue(@Query(\"since\") since: kotlin.String? = null, @Query(\"sinceBuild\") sinceBuild: kotlin.String? = null, @Query(\"maxBuilds\") maxBuilds: kotlin.Int? = null, @Query(\"maxWaitSecs\") maxWaitSecs: kotlin.Int? = null)"
384+
);
385+
}
386+
344387
private static class ModelNameTest {
345-
private String expectedName;
346-
private String expectedClassName;
388+
private final String expectedName;
389+
private final String expectedClassName;
347390

348391
private ModelNameTest(String nameAndClass) {
349392
this.expectedName = nameAndClass;

0 commit comments

Comments
 (0)