Skip to content

[kotlin] Fix the kotlinx serializer for a number branch in oneOf/anyOf wrappers - #25472

Open
fixfon wants to merge 2 commits into
OpenAPITools:masterfrom
fixfon:fix/25452-kotlin-anyof-oneof-number-encoder
Open

fixfon wants to merge 2 commits into
OpenAPITools:masterfrom
fixfon:fix/25452-kotlin-anyof-oneof-number-encoder

Conversation

@fixfon

@fixfon fixfon commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description:

With the kotlin generator, serializationLibrary=kotlinx_serialization and generateOneOfAnyOfWrappers=true, an anyOf or oneOf with an unformatted type: number branch generated a wrapper whose serialize() did not compile. The branch fell through to the {{^isPrimitiveType}} case and wrote jsonEncoder.encodeSerializableValue(java.math.BigDecimal.serializer(), value.value), and BigDecimal has no serializer().

In kotlin-client/anyof_class.mustache and oneof_class.mustache that case now writes jsonEncoder.encodeJsonElement(JsonPrimitive(value.value)) when isNumber is set. Every other non-primitive branch keeps the line it had. The change is limited to type: number without a format.

I added a test in KotlinClientCodegenModelTest with 3_0/kotlin/issue25452-anyof-oneof-number.yaml, the spec from the issue. It checks the generated AnyOfValue.kt and OneOfValue.kt and fails without the change. samples/ has no diff.

Noticed while here: the {{#isNumber}}{{#isDouble}} and {{#isFloat}} branches in these two templates are never reached, because isNumber is not set for format: double or float. A Double or Float member (also via typeMappings) therefore gets no case in serialize(). This is not addressed in this PR.

Fixes #25452

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 (70 tests). With the two templates put back to master, the new test fails.

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

  • I generated a jvm-retrofit2 client from the issue spec with the options above and built it with its own Gradle wrapper (./gradlew compileKotlin). With master templates it fails with Unresolved reference 'serializer' in AnyOfValue.kt and OneOfValue.kt. With this change, BUILD SUCCESSFUL.

  • ./bin/generate-samples.sh with the four kotlin-oneOf-*-kotlinx-serialization* configs exits 0 and leaves samples/ unchanged.

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 the Kotlin client code generator for oneOf/anyOf wrappers when a branch is an unformatted type: number, so the generated kotlinx_serialization code compiles instead of failing with an unresolvable BigDecimal.serializer() reference.

  • The number branch in anyof_class.mustache and oneof_class.mustache now writes the value as a JSON number via JsonPrimitive and deserializes it from a non-string JsonPrimitive content as BigDecimal.
  • Adds a test with a new OpenAPI spec that verifies the generated wrappers avoid BigDecimal.serializer() and decodeFromJsonElement<java.math.BigDecimal>.

Written for commit 86d21ec. Summary will update on new commits.

View guided diff

…nyOf wrappers

A plain `type: number` member maps to java.math.BigDecimal, which is not a Kotlin primitive, so the kotlinx_serialization oneOf/anyOf wrapper serializer emitted `java.math.BigDecimal.serializer()`. kotlinx.serialization has no such serializer, so the generated code did not compile. The number branch now writes the value as a JSON number via `JsonPrimitive`.

Fixes OpenAPITools#25452

@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 4 files

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

View guided diff | Re-trigger cubic

The unformatted number (java.math.BigDecimal) branch is now encoded as a JSON number, but its decode branch only ran for non-primitive JSON elements, so a number never matched. A plain Json also has no BigDecimal serializer for decodeFromJsonElement. The branch now accepts a non-string JsonPrimitive and builds the BigDecimal from its content.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][KOTLIN] kotlinx_serialization: a string-or-number anyOf/oneOf wrapper doesn't compile

1 participant