feat: add four-state JsonField and RawJson tree with additionalProperties pass-through#148
feat: add four-state JsonField and RawJson tree with additionalProperties pass-through#148OmarAlJarrah wants to merge 1 commit into
Conversation
…ties pass-through Introduce a dependency-free four-state field model for forward-compatible deserialization, alongside an immutable additionalProperties holder for lossless unknown-field round-tripping. sdk-core (zero non-stdlib deps): - RawJson: an immutable JSON value tree (Obj/Arr/Str/Num/Bool/Null). Numbers keep their verbatim literal text so large ids and high-precision decimals round-trip without the Double-precision loss common in client SDKs. - JsonField<T>: a sealed four-state container — Missing / Null / Known<T:Any> / Raw(RawJson). Raw is the "present but unbindable" escape hatch a generated, forward-compatible model needs; it preserves the original JSON instead of throwing or dropping it. Bidirectional, explicitly-lossy interop with Tristate documents the read-path (four-state) vs. PATCH-path (three-state) boundary so the two are never wrongly merged. - AdditionalProperties: an immutable, insertion-ordered snapshot of unknown properties (private ctor + Builder + newBuilder), the runtime primitive behind additionalProperties pass-through. sdk-serde-jackson: - JsonFieldModule mirrors TristateModule: contextual de/serializers, a bean-property writer that omits Missing fields, and RawJson<->Jackson node conversion that streams numbers verbatim. A value that fails to bind to T falls back to Raw rather than failing the parse. Registered in the default ObjectMapper. The default mapper already tolerates unknown fields; a model mixing in the any-setter/any-getter pattern now captures them into AdditionalProperties so a read-modify-write loop no longer silently drops server-added fields. Closes #50 Closes #52
|
This adds Issues
This directly contradicts the documented promise in Fix options: enable |
Adds a dependency-free four-state field model for forward-compatible deserialization, plus an immutable
additionalPropertiesholder for lossless unknown-field round-tripping. Both are hand-writtensdk-coreruntime primitives, fully usable today, that a future generator can target — no codegen is added.What
sdk-core (no runtime deps beyond Kotlin stdlib)
RawJson— an immutable JSON value tree (Obj/Arr/Str/Num/Bool/Null). Numbers are stored as their verbatim literal text, so largelongids and high-precision decimals survive a round-trip without theDouble-precision corruption that bites many client SDKs. Typed accessors (toLongOrNull,toBigDecimal, …) parse on demand.JsonField<T>— a sealed four-state container:Missing/Null/Known<T : Any>/Raw(RawJson).Tristatecovers the first three;JsonFieldaddsRaw, the "present but does not bind toT" escape hatch a forward-compatible model needs, capturing the original JSON instead of throwing or dropping it. It documents the read-path (four-state) vs. PATCH-path (three-state) boundary and offers explicit, intentionally-lossytoTristate()/fromTristate()interop so the two models are never wrongly merged.AdditionalProperties— an immutable, insertion-ordered snapshot of unknown properties (private ctor +BuilderimplementingBuilder<T>+ prefillednewBuilder()), the runtime primitive behindadditionalPropertiespass-through.sdk-serde-jackson
JsonFieldModulemirrorsTristateModule: contextual de/serializers, a bean-property writer that omitsMissingfields entirely (soMissingnever collapses intonullon the wire), and aRawJson↔ Jackson node converter that streams numbers verbatim. A value that fails to bind toTfalls back toRawrather than failing the parse. Registered in the defaultObjectMapper.The default mapper already tolerates unknown fields, but Jackson then drops them — a read-modify-write loop loses any server-added field. A model mixing in the
@JsonAnySetter/@JsonAnyGetterpattern now captures unknowns intoAdditionalPropertiesand re-emits them, making the round-trip lossless (a test demonstrates a large server-added id surviving unchanged).Tests
RawJsonTest,JsonFieldTest,AdditionalPropertiesTest(sdk-core) — value algebra, immutability/defensive copies, number fidelity,Tristateinterop, builder semantics.JsonFieldModuleTest,AdditionalPropertiesPassThroughTest(sdk-serde-jackson) — the four states round-trip; a wrong-typed payload becomesRawand re-emits verbatim; unknown fields are captured and survive read-modify-write.Gated build (module-scoped, run locally)
Result: BUILD SUCCESSFUL.
apiDumpwas run on both modules and the regeneratedapi/*.apifiles are committed.Closes #50
Closes #52