Repository navigation
fix: preserve Kotlin pure dictionary models - #177
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- Generate nonempty data classes for named objects whose only declared content is additional properties instead of failing empty-data-class validation. - Expose typed mutable additionalProperties storage with an empty default while reading and writing flat JSON objects without a synthetic storage wrapper. - Keep dictionary storage outside Map inheritance so Gson honors its adapter instead of selecting its built-in map codec and silently dropping null entries. - Preserve verbatim keys, nullable values, raw JSON trees, numeric precision and nested containers while delegating ordinary model values to their native codecs. - Decode entries from the original JSON reader so native integer errors propagate instead of being silently truncated or wrapped by Gson's tree-reader conversions. - Qualify authored model and dictionary types within nested containers so Gson helper imports cannot shadow their declared identities or break compilation. - Restore the writer's null policy even on failure and keep ordinary model null omission, aliases, recursive values and union member boundaries intact. - Retain HTTP request, response and typed-error dictionary payloads with native consumers on unchanged generated projects and dependency manifests. - Limit the repair to pure Kotlin dictionaries; mixed-object extension storage, shared IR, other languages and allOf wire-shape redesign remain separate.
adamcavendish
force-pushed
the
adamcavendish/kotlin-dictionary-models
branch
from
November 12, 2026 10:16
edc0ea3 to
a1e8dc3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Generate usable Kotlin models for named pure dictionaries and retain their flat
JSON entries through model and HTTP conversion.
Problem
A named object with only
additionalPropertiesreaches the Kotlin emitter as anobject with no named fields. The emitter previously ignored its dictionary value
type and attempted an empty data class, which sigil-stitch correctly rejects.
Even the single-schema
Labelsstring dictionary therefore prevents generation.Using a
Mapsubclass does not solve the full problem: Gson selects its built-inmap codec before the annotated adapter, discarding null entries and bypassing the
dictionary's object-root handling.
Behavior
Pure dictionary models now expose typed mutable
additionalPropertiesstorage,defaulting to an empty map. A private Gson adapter flattens that storage directly
to JSON object keys; no
additionalPropertieswrapper is added on the wire.Keys remain verbatim, including keys resembling renamed fields or the storage
property itself. Values retain scalar, generated-model, nullable and container
types. Opaque dictionaries use
JsonElementvalues, preserving arbitrary trees,null entries and large numeric literals. Nested containers preserve their own
entries while ordinary model-valued leaves keep their normal Gson codecs.
Entries decode directly from the original JSON reader through their declared
native codecs. Fractional or overflowing integer values retain native decode
errors instead of being silently truncated or wrapped by tree-reader conversions.
Authored model and dictionary types use their configured model-package identities,
including inside nested containers, so Gson helpers such as
TypeToken,JsonElement,JsonNullandGsoncannot replace same-named generated models.Aliases, recursive values, containing models and union boundaries use the same
dictionary representation. HTTP requests, successful responses and lazy typed
error bodies retain dictionary payloads. Root JSON null stays Kotlin null;
non-object roots fail instead of silently becoming empty dictionaries. Writers
restore the surrounding null policy even when serialization fails.
Boundaries
This is the pure Kotlin dictionary repair after merged union #176. The new path
applies only to objects with no named fields and explicit additional-property
value facts. Ordinary and mixed objects, tagged codecs, aliases, enum declarations,
shared IR, other-language generators and generated dependencies are unchanged.
Mixed-object additional-property preservation and multi-member
allOfwire-shaperedesign remain separate. Value decoding uses the retained IR representations and
existing native codecs; this is not new JSON Schema validation or a shared-lowerer
redesign. Generating the larger wire-preservation fixture does not claim that its
separate mixed-object and composition defects are fixed.