diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache index 2679b6f48881..119414e7c6bc 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache @@ -176,6 +176,9 @@ import {{packageName}}.infrastructure.ITransformForStorage {{/multiplatform}} {{/enumVars}} {{/allowableValues}} + {{#multiplatform}} + override fun toString(): kotlin.String = value{{^isString}}.toString(){{/isString}} + {{/multiplatform}} } {{#kotlinx_serialization}} {{#enumUnknownDefaultCase}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache index cf5a4fe733e7..59309e7bc71a 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache @@ -46,15 +46,16 @@ import kotlinx.serialization.encoding.* {{^enumUnknownDefaultCase}} {{#allowableValues}}{{#enumVars}} @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) - {{&name}}({{{value}}}){{^-last}},{{/-last}} + {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} {{/enumVars}}{{/allowableValues}} {{/enumUnknownDefaultCase}} {{#enumUnknownDefaultCase}} {{#allowableValues}}{{#enumVars}}{{^-last}} - @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) - {{&name}}({{{value}}}), + @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) + {{&name}}({{{value}}}); {{/-last}}{{/enumVars}}{{/allowableValues}} {{/enumUnknownDefaultCase}} + override fun toString(): kotlin.String = value{{^isString}}.toString(){{/isString}} } {{/isEnum}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java index 115151324b47..76df9479ca23 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -43,12 +43,13 @@ import java.util.Map; import static org.openapitools.codegen.CodegenConstants.*; -import static org.openapitools.codegen.languages.KotlinClientCodegen.COMPANION_OBJECT; -import static org.openapitools.codegen.languages.KotlinClientCodegen.GENERATE_ONEOF_ANYOF_WRAPPERS; +import static org.openapitools.codegen.languages.KotlinClientCodegen.*; @SuppressWarnings("static-method") public class KotlinClientCodegenModelTest { + private static final String KOTLIN_GENERATOR = "kotlin"; + private Schema getArrayTestSchema() { return new ObjectSchema() .description("a sample model") @@ -369,7 +370,7 @@ public void testNativeClientExplodedQueryParamObject() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(properties) .setInputSpec("src/test/resources/3_0/issue4808.yaml") @@ -392,7 +393,7 @@ public void testOmitGradleWrapperDoesNotGenerateWrapper() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setInputSpec("src/test/resources/3_0/ping.yaml") .addAdditionalProperty("omitGradleWrapper", true) .setOutputDir(output.getAbsolutePath().replace("\\", "/")); @@ -495,7 +496,7 @@ public void testLocalVariablesUseSanitizedDataTypeNamesForOneOfProperty_19942(Cl output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary(clientLibrary.getLibraryName()) .setInputSpec("src/test/resources/3_0/issue_19942.json") .addAdditionalProperty("omitGradleWrapper", true) @@ -519,7 +520,7 @@ public void testLocalVariablesUseSanitizedDataTypeNamesForAnyOfProperty_19942(Cl output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary(clientLibrary.getLibraryName()) .setInputSpec("src/test/resources/3_0/issue_19942.json") .addAdditionalProperty("omitGradleWrapper", true) @@ -582,7 +583,7 @@ public void polymorphicReferenceOverrides() throws IOException { // File output = Paths.get("/Users/sylvain_maillard/workspaces/openapi-generator/modules/openapi-generator/target/test").toFile(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setInputSpec("src/test/resources/3_1/issue_22216.yaml") .setOutputDir(output.getAbsolutePath().replace("\\", "/")); @@ -607,7 +608,7 @@ public void polymorphicKotlinxSerialization() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "kotlinx_serialization"); @@ -647,7 +648,7 @@ public void oneOfPrimitiveKotlinxSerialization() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "kotlinx_serialization"); @@ -682,7 +683,7 @@ public void anyOfPrimitiveKotlinxSerialization() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "kotlinx_serialization"); @@ -748,7 +749,7 @@ private File generateKotlinxOneOfAnyOf(Map extraProps) throws IO props.putAll(extraProps); new DefaultGenerator() .opts(new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(props) .setInputSpec("src/test/resources/3_0/issue_19942.json") @@ -768,7 +769,7 @@ public void polymorphicJacksonSerialization() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-okhttp4") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -824,7 +825,7 @@ public void testIntArrayToEnum() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-ktor") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -850,7 +851,7 @@ public void testBooleanConstEnumUsesBooleanLiteral() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-ktor") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -880,7 +881,7 @@ public void testJacksonEnumsUseJsonCreator() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -906,7 +907,7 @@ public void testJacksonNestedEnumsUseJsonValue() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -934,7 +935,7 @@ public void testJacksonEnumsThrowForUnknownValue() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -960,7 +961,7 @@ public void testJacksonEnumsExposeDecodeOrNullHelper() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -993,7 +994,7 @@ public void testJacksonEnumsWithUnknownDefaultCase() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setLibrary("jvm-retrofit2") .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); @@ -1016,6 +1017,74 @@ public void testJacksonEnumsWithUnknownDefaultCase() throws IOException { TestUtils.assertFileNotContains(enumKt, "throw IllegalArgumentException(\"Unknown ExampleNumericEnum value"); } + @Test + public void testMultiplatformEnumWithUnknownDefaultAndCustomVariableNamesOverridesToString() throws IOException { + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(KOTLIN_GENERATOR) + .setLibrary("multiplatform") + .setAdditionalProperties(new HashMap<>() {{ + put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); + put(CodegenConstants.MODEL_PACKAGE, "model"); + put("dateLibrary", "kotlinx-datetime"); + put(ENUM_UNKNOWN_DEFAULT_CASE, "true"); + }}) + .setInputSpec("src/test/resources/3_0/kotlin/issue23764-multiplatform-inline-enum-serialization.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + + generator.opts(clientOptInput).generate(); + + final Path definedEnumKt = Paths.get(output + "/src/commonMain/kotlin/model/ApiError.kt"); + final Path inlineEnumKt = Paths.get(output + "/src/commonMain/kotlin/model/AllowFoo.kt"); + final Path headerEnumKt = Paths.get(output + "/src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt"); + + TestUtils.assertFileContains(definedEnumKt, "override fun toString(): kotlin.String = value.toString()"); + TestUtils.assertFileContains(definedEnumKt, "@SerialName(value = \"11184809\") unknown_default_open_api(11184809);"); + TestUtils.assertFileContains(inlineEnumKt, "override fun toString(): kotlin.String = value"); + TestUtils.assertFileContains(inlineEnumKt, "unknown_default_open_api(\"unknown_default_open_api\");"); + TestUtils.assertFileContains(headerEnumKt, "override fun toString(): kotlin.String = value"); + // The enumUnknownDefaultCase should be omitted for query parameters + TestUtils.assertFileContains(headerEnumKt, "ALLOW(\"1\");"); + } + + @Test + public void testMultiplatformEnumWithCustomVariableNamesOverridesToString() throws IOException { + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(KOTLIN_GENERATOR) + .setLibrary("multiplatform") + .setAdditionalProperties(new HashMap<>() {{ + put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); + put(CodegenConstants.MODEL_PACKAGE, "model"); + put("dateLibrary", "kotlinx-datetime"); + }}) + .setInputSpec("src/test/resources/3_0/kotlin/issue23764-multiplatform-inline-enum-serialization.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + + generator.opts(clientOptInput).generate(); + + final Path definedEnumKt = Paths.get(output + "/src/commonMain/kotlin/model/ApiError.kt"); + final Path inlineEnumKt = Paths.get(output + "/src/commonMain/kotlin/model/AllowFoo.kt"); + final Path headerEnumKt = Paths.get(output + "/src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt"); + + TestUtils.assertFileContains(definedEnumKt, "override fun toString(): kotlin.String = value.toString()"); + TestUtils.assertFileContains(definedEnumKt, "@SerialName(value = \"100\") ERROR(100);"); + TestUtils.assertFileContains(inlineEnumKt, "override fun toString(): kotlin.String = value"); + TestUtils.assertFileContains(inlineEnumKt, "ALLOW(\"1\");"); + TestUtils.assertFileContains(headerEnumKt, "override fun toString(): kotlin.String = value"); + TestUtils.assertFileContains(headerEnumKt, "ALLOW(\"1\");"); + } + @Test(description = "convert an empty model to object") public void emptyModelKotlinxSerializationTest() throws IOException { final Schema schema = new ObjectSchema() @@ -1030,7 +1099,7 @@ public void emptyModelKotlinxSerializationTest() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setAdditionalProperties(new HashMap<>() {{ put(CodegenConstants.MODEL_PACKAGE, "model"); put(GENERATE_ONEOF_ANYOF_WRAPPERS, false); @@ -1079,7 +1148,7 @@ public void testCompanionObjectGeneratesCompanionInModel() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .addAdditionalProperty(COMPANION_OBJECT, true) .setInputSpec("src/test/resources/3_0/petstore.yaml") .setOutputDir(output.getAbsolutePath().replace("\\", "/")); @@ -1099,7 +1168,7 @@ public void paramJsonPropertyAnnotationWithNameMappings() throws IOException { output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setInputSpec("src/test/resources/3_0/kotlin/param-json-property.yaml") .setOutputDir(output.getAbsolutePath().replace("\\", "/")) .addAdditionalProperty(CodegenConstants.SERIALIZATION_LIBRARY, "jackson") @@ -1123,7 +1192,7 @@ public void paramJsonPropertyAnnotationWithDigitStartingPropertyName() throws IO output.deleteOnExit(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("kotlin") + .setGeneratorName(KOTLIN_GENERATOR) .setInputSpec("src/test/resources/3_0/kotlin/param-json-property.yaml") .setOutputDir(output.getAbsolutePath().replace("\\", "/")) .addAdditionalProperty(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); diff --git a/modules/openapi-generator/src/test/resources/3_0/kotlin/issue23764-multiplatform-inline-enum-serialization.yaml b/modules/openapi-generator/src/test/resources/3_0/kotlin/issue23764-multiplatform-inline-enum-serialization.yaml new file mode 100644 index 000000000000..9e08d9889f9c --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/kotlin/issue23764-multiplatform-inline-enum-serialization.yaml @@ -0,0 +1,65 @@ +openapi: 3.0.3 +info: + description: >- + Example created + version: 1.0.0 + title: OpenAPI Stuff API created to reproduce issue + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +paths: + /healthcheck: + get: + parameters: + - name: X-Allow-Foo + in: header + schema: + type: string + enum: + - '0' + - '1' + x-enum-varnames: + - DISALLOW + - ALLOW + summary: Health check endpoint. + operationId: healthcheck + responses: + 204: + description: Successful health check + default: + description: Unexpected error + content: + 'application/json': + schema: + $ref: '#/components/schemas/ApiError' + +components: + schemas: + ApiError: + required: + - errorCode + type: object + properties: + errorCode: + type: integer + enum: + - 0 + - 100 + x-enum-varnames: + - OK + - ERROR + reasonCode: + $ref: '#/components/schemas/ReasonCode' + ReasonCode: + type: integer + enum: + - 10 + - 20 + AllowFoo: + type: string + enum: + - '0' + - '1' + x-enum-varnames: + - DISALLOW + - ALLOW diff --git a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt index 8140d4711620..426caf13c53e 100644 --- a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt @@ -135,8 +135,9 @@ open class PetApi : ApiClient { pending("pending"), @SerialName(value = "sold") - sold("sold") + sold("sold"); + override fun toString(): kotlin.String = value.toString() } /** diff --git a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Order.kt b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Order.kt index 36b2997c7f5a..63604f0bd855 100644 --- a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Order.kt +++ b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Order.kt @@ -67,6 +67,7 @@ data class Order ( @SerialName(value = "placed") placed("placed"), @SerialName(value = "approved") approved("approved"), @SerialName(value = "delivered") delivered("delivered"); + override fun toString(): kotlin.String = value } } diff --git a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt index 3d2dc5408719..c12046564603 100644 --- a/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt +++ b/samples/client/petstore/kotlin-multiplatform-kotlinx-datetime/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt @@ -69,6 +69,7 @@ data class Pet ( @SerialName(value = "available") available("available"), @SerialName(value = "pending") pending("pending"), @SerialName(value = "sold") sold("sold"); + override fun toString(): kotlin.String = value } } diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt index 8140d4711620..426caf13c53e 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/apis/PetApi.kt @@ -135,8 +135,9 @@ open class PetApi : ApiClient { pending("pending"), @SerialName(value = "sold") - sold("sold") + sold("sold"); + override fun toString(): kotlin.String = value.toString() } /** diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Order.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Order.kt index 36b2997c7f5a..63604f0bd855 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Order.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Order.kt @@ -67,6 +67,7 @@ data class Order ( @SerialName(value = "placed") placed("placed"), @SerialName(value = "approved") approved("approved"), @SerialName(value = "delivered") delivered("delivered"); + override fun toString(): kotlin.String = value } } diff --git a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt index 3d2dc5408719..c12046564603 100644 --- a/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt +++ b/samples/client/petstore/kotlin-multiplatform/src/commonMain/kotlin/org/openapitools/client/models/Pet.kt @@ -69,6 +69,7 @@ data class Pet ( @SerialName(value = "available") available("available"), @SerialName(value = "pending") pending("pending"), @SerialName(value = "sold") sold("sold"); + override fun toString(): kotlin.String = value } }