Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
{{/enumUnknownDefaultCase}}
{{#hasEnums}}
{{^enumUnknownDefaultCase}}
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
{{/enumUnknownDefaultCase}}
{{/hasEnums}}
{{#discriminator}}
import kotlinx.serialization.ExperimentalSerializationApi
Expand Down Expand Up @@ -144,7 +150,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
*/
{{^multiplatform}}
{{#kotlinx_serialization}}
{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{#enumUnknownDefaultCase}}(with = {{{nameInPascalCase}}}Serializer::class){{/enumUnknownDefaultCase}}{{/serializableModel}}
{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{#enumUnknownDefaultCase}}(with = {{{nameInPascalCase}}}Serializer::class){{/enumUnknownDefaultCase}}{{/serializableModel}}{{^enumUnknownDefaultCase}}{{^isString}}{{^isNumber}}{{^isContainer}}(with = {{{nameInPascalCase}}}Serializer::class){{/isContainer}}{{/isNumber}}{{/isString}}{{/enumUnknownDefaultCase}}
{{/kotlinx_serialization}}
{{#moshi}}
@JsonClass(generateAdapter = false)
Expand Down Expand Up @@ -201,6 +207,30 @@ import {{packageName}}.infrastructure.ITransformForStorage
}
}
{{/enumUnknownDefaultCase}}
{{^multiplatform}}
{{^enumUnknownDefaultCase}}
{{^isString}}
{{^isNumber}}
{{^isContainer}}

internal object {{nameInPascalCase}}Serializer : KSerializer<{{nameInPascalCase}}> {
override val descriptor = {{dataType}}.serializer().descriptor

override fun deserialize(decoder: Decoder): {{nameInPascalCase}} {
val value = decoder.decodeSerializableValue({{dataType}}.serializer())
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
return {{nameInPascalCase}}.entries.firstOrNull { it.value == value }
?: throw IllegalArgumentException("Unknown enum value: $value")
}

override fun serialize(encoder: Encoder, value: {{nameInPascalCase}}) {
encoder.encodeSerializableValue({{dataType}}.serializer(), value.value)
}
}
{{/isContainer}}
{{/isNumber}}
{{/isString}}
{{/enumUnknownDefaultCase}}
{{/multiplatform}}
{{/kotlinx_serialization}}
{{/isEnum}}
{{/vars}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1582,4 +1582,68 @@ public void testEnumUnknownDefaultCaseIsRegisteredAsCliOption() {
Assert.assertEquals(option.getDefault(), "false");
Assert.assertEquals(option.getEnum().keySet(), Set.of("true", "false"));
}

private Path generateKotlinxInlineNumericEnumModels(boolean serializableModel) throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName(KOTLIN_GENERATOR)
.setInputSpec("src/test/resources/3_0/kotlin/issue25459-kotlinx-inline-numeric-enum.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"))
.addAdditionalProperty(CodegenConstants.SERIALIZATION_LIBRARY, "kotlinx_serialization")
.addAdditionalProperty(CodegenConstants.SERIALIZABLE_MODEL, serializableModel);

DefaultGenerator generator = new DefaultGenerator();
generator.opts(configurator.toClientOptInput()).generate();

return Paths.get(output.getAbsolutePath(), "src/main/kotlin/org/openapitools/client/models");
}

@Test
public void testKotlinxSerializationInlineNumericEnumUsesValueSerializer() throws IOException {
Path models = generateKotlinxInlineNumericEnumModels(false);
Path recordingKt = models.resolve("Recording.kt");

// A plain @Serializable enum is written by serial name, so Plays would be the JSON string "1"
// instead of the number 1. The value serializer reads and writes the Int itself.
TestUtils.assertFileContains(recordingKt,
"@Serializable(with = PlaysSerializer::class)",
"enum class Plays(val value: kotlin.Int)",
"internal object PlaysSerializer : KSerializer<Plays>",
"decoder.decodeSerializableValue(kotlin.Int.serializer())",
"encoder.encodeSerializableValue(kotlin.Int.serializer(), value.value)",
"import kotlinx.serialization.KSerializer",
"import kotlinx.serialization.builtins.serializer",
"import kotlinx.serialization.encoding.Decoder",
"import kotlinx.serialization.encoding.Encoder");
// String enums stay on their @SerialName values.
TestUtils.assertFileNotContains(recordingKt, "ModeSerializer");
// Models without enums must not pick up the serializer imports.
TestUtils.assertFileNotContains(models.resolve("Label.kt"), "KSerializer");
}

@Test
public void testKotlinxSerializationInlineBigDecimalEnumKeepsPlainSerializable() throws IOException {
Path recordingKt = generateKotlinxInlineNumericEnumModels(false).resolve("Recording.kt");

// type: number maps to java.math.BigDecimal, which has no serializer() to build a value serializer from.
TestUtils.assertFileContains(recordingKt,
"@Serializable enum class Ratio(val value: java.math.BigDecimal)");
TestUtils.assertFileNotContains(recordingKt, "RatioSerializer", "java.math.BigDecimal.serializer()");
// type: number with format double maps to kotlin.Double and keeps the value serializer.
TestUtils.assertFileContains(recordingKt,
"@Serializable(with = WeightSerializer::class)",
"encoder.encodeSerializableValue(kotlin.Double.serializer(), value.value)");
}

@Test
public void testKotlinxSerializationInlineNumericEnumUsesValueSerializerForSerializableModel() throws IOException {
// serializableModel imports kotlinx's Serializable under the alias KSerializable.
Path recordingKt = generateKotlinxInlineNumericEnumModels(true).resolve("Recording.kt");

TestUtils.assertFileContains(recordingKt,
"@KSerializable(with = PlaysSerializer::class)",
"internal object PlaysSerializer : KSerializer<Plays>");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
openapi: 3.0.3
info:
title: 'Issue 25459 kotlinx_serialization inline numeric enum'
version: latest
paths:
'/recording':
get:
operationId: getRecording
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Recording'
components:
schemas:
Recording:
type: object
required: [plays, mode, speed]
properties:
plays:
type: integer
enum: [1, 2]
mode:
type: string
enum: [fast, slow]
ratio:
type: number
enum: [0.5, 1.5]
weight:
type: number
format: double
enum: [0.25, 0.75]
speed:
$ref: '#/components/schemas/Speed'
label:
$ref: '#/components/schemas/Label'
Speed:
type: integer
enum: [1, 2]
Label:
type: object
properties:
text:
type: string
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ package org.openapitools.client.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* An order for a pets from the pet store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import org.openapitools.client.models.Tag
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* A pet for sale in the pet store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ package org.openapitools.client.models
import kotlinx.serialization.Serializable as KSerializable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.io.Serializable

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import org.openapitools.client.models.Tag
import kotlinx.serialization.Serializable as KSerializable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.io.Serializable

/**
Expand Down
Loading