Skip to content

Commit 5a0fa87

Browse files
authored
[kotlin] Fix inline enum array parameter default values (#24940)
An array parameter with inline enum items and a default was rendered as an enum class reference that does not exist for operation parameters, and the jvm-ktor client then mangled it further into an invalid identifier. Parameter defaults for such arrays now use the plain item values, e.g. setOf("red","blue"), which fixes jvm-ktor, jvm-volley and javalin5/6. Fixes #24851
1 parent 88aeaad commit 5a0fa87

5 files changed

Lines changed: 111 additions & 2 deletions

File tree

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,10 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
12791279
}
12801280

12811281
private String toArrayDefaultValue(CodegenProperty cp, Schema schema) {
1282+
return toArrayDefaultValue(cp, schema, false);
1283+
}
1284+
1285+
private String toArrayDefaultValue(CodegenProperty cp, Schema schema, boolean inlineEnumItemsAsLiterals) {
12821286
if (schema.getDefault() != null) {
12831287
String arrInstantiationType = ModelUtils.isSet(schema) ? "set" : "arrayList";
12841288

@@ -1295,7 +1299,10 @@ private String toArrayDefaultValue(CodegenProperty cp, Schema schema) {
12951299
_default.elements().forEachRemaining((element) -> {
12961300
String defaultValue = element.asText();
12971301
if (defaultValue != null) {
1298-
if (cp.items.getIsEnumOrRef()) {
1302+
boolean itemIsLiteral = inlineEnumItemsAsLiterals && cp.items.isEnum;
1303+
if (itemIsLiteral && ModelUtils.isStringSchema(itemsSchema)) {
1304+
defaultContent.append("\"").append(escapeText(defaultValue)).append("\"").append(",");
1305+
} else if (cp.items.getIsEnumOrRef() && !itemIsLiteral) {
12991306
String className = cp.items.datatypeWithEnum;
13001307
String enumVarName = toEnumVarName(defaultValue, cp.items.dataType);
13011308
defaultContent.append(className).append(".").append(enumVarName).append(",");
@@ -1314,6 +1321,12 @@ private String toArrayDefaultValue(CodegenProperty cp, Schema schema) {
13141321

13151322
@Override
13161323
public String toDefaultParameterValue(CodegenProperty cp, Schema schema) {
1324+
Schema<?> referencedSchema = ModelUtils.getReferencedSchema(this.openAPI, schema);
1325+
if (ModelUtils.isArraySchema(referencedSchema) && cp.items != null && cp.items.isEnum) {
1326+
// inline enum items of a parameter have no enum class of their own,
1327+
// so the default must use the plain item values (e.g. setOf("a", "b"))
1328+
return toArrayDefaultValue(cp, referencedSchema, true);
1329+
}
13171330
return toDefaultValue(cp, schema);
13181331
}
13191332

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@ private void propagateParamBaseNameToVars(CodegenParameter param) {
12231223
* @param param codegen parameter
12241224
*/
12251225
private void adjustEnumRefDefault(CodegenParameter param) {
1226-
if (StringUtils.isEmpty(param.defaultValue) || !(param.isEnum || param.isEnumRef)) {
1226+
if (StringUtils.isEmpty(param.defaultValue) || param.isContainer || !(param.isEnum || param.isEnumRef)) {
12271227
return;
12281228
}
12291229

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,30 @@ public void testEnumDefaultForReferencedSchemaParameterJvmOkhttp4() throws IOExc
137137
assertFileContains(statusApi.toPath(), "state: PetStatus? = PetStatus.AVAILABLE");
138138
}
139139

140+
@DataProvider(name = "librariesWithPlainInlineEnumParams")
141+
public static Object[][] librariesWithPlainInlineEnumParams() {
142+
return new Object[][]{
143+
{ClientLibrary.JVM_KTOR},
144+
{ClientLibrary.JVM_VOLLEY}
145+
};
146+
}
147+
148+
@Test(dataProvider = "librariesWithPlainInlineEnumParams")
149+
public void testInlineEnumArrayDefaultUsesItemValues_24851(ClientLibrary library) throws IOException {
150+
OpenAPI openAPI = readOpenAPI("3_0/kotlin/issue24851-enum-array-default-query.yaml");
151+
152+
KotlinClientCodegen codegen = createCodegen(library);
153+
DefaultGenerator generator = new DefaultGenerator();
154+
enableOnlyApiGeneration(generator);
155+
156+
List<File> files = generator.opts(createClientOptInput(openAPI, codegen)).generate();
157+
File defaultApi = files.stream().filter(file -> file.getName().equals("DefaultApi.kt")).findAny().orElseThrow();
158+
159+
assertFileContains(defaultApi.toPath(), "colors: kotlin.collections.Set<kotlin.String>? = setOf(\"red\",\"blue\")");
160+
assertFileContains(defaultApi.toPath(), "sizes: kotlin.collections.List<kotlin.Int>? = arrayListOf(2)");
161+
assertFileContains(defaultApi.toPath(), "refColors: kotlin.collections.List<Color>? = arrayListOf(Color.RED)");
162+
}
163+
140164
@Test(dataProvider = "clientLibraries")
141165
void testEnumReservedDefaultNotHtmlEscaped(ClientLibrary library) throws IOException {
142166
OpenAPI openAPI = readOpenAPI("src/test/resources/3_0/kotlin/enum-default-query-reserved-word.json");

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,37 @@ private Object[][] createData() {
283283
new Object[]{JAVALIN6},
284284
};
285285
}
286+
@DataProvider(name = "javalinLibraries")
287+
private Object[][] javalinLibraries() {
288+
return new Object[][]{
289+
new Object[]{JAVALIN5},
290+
new Object[]{JAVALIN6},
291+
};
292+
}
293+
294+
@Test(description = "Issue #24851", dataProvider = "javalinLibraries")
295+
public void inlineEnumArrayParameterDefaultUsesItemValues(String library) throws IOException {
296+
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
297+
output.deleteOnExit();
298+
299+
KotlinServerCodegen codegen = new KotlinServerCodegen();
300+
codegen.setOutputDir(output.getAbsolutePath());
301+
codegen.additionalProperties().put(LIBRARY, library);
302+
303+
new DefaultGenerator().opts(new ClientOptInput()
304+
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/kotlin/issue24851-enum-array-default-query.yaml"))
305+
.config(codegen))
306+
.generate();
307+
308+
Path service = Paths.get(output.getAbsolutePath() + "/src/main/kotlin/org/openapitools/server/apis/DefaultApiService.kt");
309+
assertFileContains(
310+
service,
311+
"colors: kotlin.collections.Set<kotlin.String> = setOf(\"red\",\"blue\")",
312+
"sizes: kotlin.collections.List<kotlin.Int> = arrayListOf(2)",
313+
"refColors: kotlin.collections.List<Color> = arrayListOf(Color.RED)"
314+
);
315+
}
316+
286317
@Test(description = "Issue #20960", dataProvider = "dollarEscapeTest")
287318
public void givenSchemaObjectPropertyNameContainsDollarSignWhenGenerateThenDollarSignIsProperlyEscapedInAnnotation(String library) throws Exception {
288319
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Inline enum array default test
4+
version: 1.0.0
5+
paths:
6+
/items:
7+
get:
8+
operationId: getItems
9+
parameters:
10+
- name: colors
11+
in: query
12+
schema:
13+
type: array
14+
uniqueItems: true
15+
items:
16+
type: string
17+
enum: [red, blue]
18+
default: [red, blue]
19+
- name: sizes
20+
in: query
21+
schema:
22+
type: array
23+
items:
24+
type: integer
25+
enum: [1, 2]
26+
default: [2]
27+
- name: refColors
28+
in: query
29+
schema:
30+
type: array
31+
items:
32+
$ref: '#/components/schemas/Color'
33+
default: [RED]
34+
responses:
35+
"204":
36+
description: No content
37+
components:
38+
schemas:
39+
Color:
40+
type: string
41+
enum: [RED, BLUE]

0 commit comments

Comments
 (0)