Skip to content

fix(kotlin): keep null-valued columns when casting response data - #2105

Merged
abnegate merged 2 commits into
mainfrom
fix/kotlin-keep-null-data
Oct 18, 2026
Merged

abnegate merged 2 commits into
mainfrom
fix/kotlin-keep-null-data

Conversation

@abnegate

@abnegate abnegate commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

What

  • Fix: jsonCast() in the Android and Kotlin templates now serializes with requestGson, which calls serializeNulls(), instead of the default gson.
  • Tests: a new JsonCastTest in both SDKs.

Why

jsonCast() builds Row.data/Document.data from the response map, and it used the default Gson, which omits nulls. So on Android and Kotlin a column whose value is null disappeared from row.data:

  • Null and unselected look the same: a row with note: null read the same as a row whose query never selected note.
  • Left joins lose columns: an unmatched left join lost its joined columns (c.name) instead of returning them as null.
  • Realtime payloads cast through jsonCast() lost null fields the same way.

Web, Node, Python, PHP, Dart, React Native and Apple all keep them.

Found while running the query-lib case suite, 47 cases plus a builder chain, through every popular SDK against server-ce main. Every SDK except Android matched the web SDK exactly. Android differed only in null-valued keys: note on 40 rows, and c.name/customers.name on unmatched left-join rows.

Before / after

Check main This PR
JsonCastTest (Kotlin, JVM) 2 fail (AssertionError at the containsKey checks) 2/2 pass
JsonCastTest (Android, JVM unit) 2 fail (AssertionError at the containsKey checks) 2/2 pass
Query case suite through the Android SDK on an emulator (API 36) against server-ce main 15/48 cases identical to web (null keys missing) 48/48 identical

ktlint 1.8.0 is clean on the generated Kotlin and Android SDKs.

🤖 Generated with Claude Code

jsonCast() round-tripped through the default Gson, which omits nulls,
so Row.data and Document.data on Android and Kotlin lost every column
whose value is null. A null column then read the same as one the query
did not select, and the joined columns of an unmatched left join
vanished instead of reading null. Realtime payload casts lost null
fields the same way. Every other SDK keeps them.

jsonCast() now serializes with the null-preserving Gson already used
for request bodies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hansi-codes

hansi-codes Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The updated tests still exercise null preservation for flat and nested maps, and I found no issue in these incremental changes.

The Kotlin and Android templates now serialize jsonCast() inputs with null-preserving Gson, so null-valued response columns survive conversion. Both generated SDKs register tests for null keys in flat maps and nested response data.

Latest changes: The newest commits replace the Row-model-specific test cases with nested response-data map casts, avoiding a dependency on a generated Row model in the test fixture.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 6
File Change
src/SDK/Language/Android.php Registers the generated Android JsonCast test.
src/SDK/Language/Kotlin.php Registers the generated Kotlin JsonCast test.
templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig Uses null-preserving Gson for both Android jsonCast overloads.
templates/android/library/src/test/java/io/package/JsonCastTest.kt.twig Tests null preservation for flat casts and nested response data.
templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig Uses null-preserving Gson for both Kotlin jsonCast overloads.
templates/kotlin/src/test/kotlin/io/appwrite/JsonCastTest.kt.twig Tests null preservation for flat casts and nested response data.

Reviewed the commits since dde554f · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Tier S · Looks good to merge. Summary

The generator's test spec has no Row model, so the test casts the data
map Row.from() hands to jsonCast() directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abnegate
abnegate merged commit 0c394a1 into main Oct 18, 2026
61 checks passed
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.

1 participant