Skip to content

[kotlin] Serialize inline number enums by value with kotlinx_serialization - #25473

Merged
wing328 merged 2 commits into
OpenAPITools:masterfrom
fixfon:fix/25459-kotlin-inline-number-enum-serializer
Oct 30, 2026
Merged

wing328 merged 2 commits into
OpenAPITools:masterfrom
fixfon:fix/25459-kotlin-inline-number-enum-serializer

Conversation

@fixfon

@fixfon fixfon commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description:

With serializationLibrary=kotlinx_serialization, a number enum declared inline on a property (plays: { type: integer, enum: [1, 2] }) was written as the JSON string "1" and could not be read from the number 1. The same enum declared as its own schema already works, because #21746 gave enum_class.mustache a value serializer for every non-string enum. data_class.mustache only added (with = …Serializer::class) and the serializer object under enumUnknownDefaultCase.

kotlin-client/data_class.mustache now does the same as enum_class.mustache for inline enums: when enumUnknownDefaultCase is off and the enum is not a string or container, the nested enum gets @Serializable(with = <Name>Serializer::class) and an internal object <Name>Serializer that reads and writes value with the enum's type serializer. The enumUnknownDefaultCase path is unchanged. The needed kotlinx.serialization imports are added when the model has enums. The serializer object is not emitted for multiplatform, which is out of scope here: inline number enums there still behave as before. Number (BigDecimal) enums keep the previous plain @serializable path; supporting them properly needs a toEnumValue change across Kotlin generators, so I left that out of scope.

I added two tests in KotlinClientCodegenModelTest with 3_0/kotlin/issue25459-kotlinx-inline-numeric-enum.yaml, one for @Serializable and one for serializableModel=true (@KSerializable). Both fail without the change. Regenerating the kotlinx samples adds the four imports to Pet.kt and Order.kt in kotlin-jvm-ktor-kotlinx_serialization and kotlin-retrofit2-kotlinx_serialization. Their inline enums are strings, so nothing else in them changes.

Fixes #25459

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples (see below for what I ran instead):
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

What I ran on this branch (macOS, JDK 21, Maven wrapper):

  • ./mvnw -pl modules/openapi-generator -am test -Dtest=KotlinClientCodegenModelTest passes (71 tests). With data_class.mustache put back to master, the two new tests fail.

  • ./mvnw -pl modules/openapi-generator -am test -Dtest=KotlinClientCodegenModelTest,KotlinClientCodegenApiTest,KotlinModelCodegenTest passes (126 tests, 0 failures, 4 skipped).

  • Both changed samples compile with their own Gradle wrapper (./gradlew compileKotlin).

  • I generated a jvm-retrofit2 kotlinx client from the issue spec and added a small round-trip test locally (not committed). With this change, Recording(plays = _1, speed = _1) encodes as {"plays":1,"speed":1} and {"plays":2,"speed":2} decodes. With master templates it encodes {"plays":"1","speed":1} and decoding fails with JsonDecodingException. The same test passes with serializableModel=true.

  • ./bin/generate-samples.sh with the ten configs that set serializationLibrary: kotlinx_serialization, plus kotlin-multiplatform.yaml and kotlin-enum-integers-multiplatform.yaml, exits 0. Only the four files above change.

I did not run the full ./mvnw clean package, the other sample configs or ./bin/utils/export_docs_generators.sh, so the second box is unchecked. No option or docs text changed.

cc @karismann @Zomzog @andrewemery @4brunu @yutaka0m @stefankoppier @e5l


Summary by cubic

Fixes inline non-string enum serialization in Kotlin clients using kotlinx_serialization. An integer enum declared inline on a property (enum: [1, 2]) was written as the JSON string "1" and failed to decode from the number 1; it now serializes and deserializes by value with a generated KSerializer, matching standalone enums.

  • Applies to integer, long, float, and double enums only when enumUnknownDefaultCase is off; that code path is unchanged.
  • type: number (BigDecimal) enums keep the previous @Serializable path because BigDecimal has no matching serializer().
  • multiplatform output is unchanged.
  • Regenerated samples gained only the new kotlinx.serialization imports because their inline enums are strings.

Written for commit 64aec35. Summary will update on new commits.

View guided diff

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

… kotlinx_serialization

Inline enums on a model were annotated with a plain @serializable, so kotlinx.serialization wrote integer and number enums by their @SerialName, as the JSON string "1" instead of the number 1. Inline non-string, non-container enums now get the same value serializer as standalone enums when enumUnknownDefaultCase is off. Models with enums import the serializer types, and multiplatform output is unchanged.

Fixes OpenAPITools#25459
…tlinx_serialization

type: number maps to java.math.BigDecimal, which has no serializer() for the generated value serializer to call, so these enums referenced an unresolved symbol. Inline number enums keep the plain @serializable they had before, while integer, long, float and double enums still use the value serializer.
@fixfon
fixfon force-pushed the fix/25459-kotlin-inline-number-enum-serializer branch from 311f84b to 64aec35 Compare October 30, 2026 08:34

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

View guided diff | Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][Kotlin] Inline number enums are serialized as strings with kotlinx_serialization

2 participants