Skip to content

fix: preserve Java untagged-union member payloads - #175

Merged
adamcavendish merged 1 commit into
mainfrom
adamcavendish/java-untagged-union-selection
Nov 11, 2026
Merged

adamcavendish merged 1 commit into
mainfrom
adamcavendish/java-untagged-union-selection

Conversation

@adamcavendish

@adamcavendish adamcavendish commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Preserve Java OkHttp untagged-union member payloads with enum-aware structural
selection and configurable typed or raw adapters.

Problem

The existing Gson adapter chooses named object members by required keys alone.
Members with the same required keys but disjoint numeric enums therefore select
the first variant and silently discard fields from the actual matching member.
The same loss occurs through containing model fields, lists, and maps.

Behavior

Policy Result
firstMatch (default) Select the first structural match in schema order, before opaque fallbacks.
strict Reject multiple authored concrete matches before decoding the selected member.
raw Emit VariantRaw(JsonElement) and preserve known, ambiguous, unmatched, null JSON.

Typed selection uses finite scalar constraints, required wire keys, nested
containers, and recursive schema facts. Numeric comparisons retain large-integer
distinctions and match scientific notation through exact significands and
unbounded exponents, without Gson's decimal-accessor scale limit. Each selected
member is decoded once through its original Gson codec; nested errors and native
decoder limits are not hidden by another member or fallback. Recursive matching
reuses both successful and failed results within one selection, with private
runtime types qualified against generated model-name collisions.

These adapters also apply to HTTP response bodies and lazily decoded typed error
bodies. Raw serialization retains null-valued entries without changing the
surrounding Gson writer's null policy.

Compatibility

  • The default and strict modes retain existing sealed interfaces, record cases,
    payload types, serialization, and typed root-null behavior. Explicit raw mode
    changes the union API to a raw record case; colliding case names are disambiguated.
  • Ordinary models, tagged unions, and existing alias/allOf wrapper codecs remain
    unchanged. Selection is not full JSON Schema validation and does not redefine
    native format, numeric-bound, coercion, or overflow behavior.
  • Dictionary/additional-property preservation and multi-member allOf redesign are
    separate repairs. Kotlin and all other language generators remain unchanged.

@codecov

codecov Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.61154% with 73 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/generators/java/okhttp/matching.rs 84.00% 68 Missing ⚠️
src/generators/java/okhttp/union.rs 96.69% 4 Missing ⚠️
src/generators/java/okhttp/sigil_emit.rs 98.57% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

- Select Java OkHttp union members using retained finite scalar and structural
  facts so unconstrained Gson fields cannot swallow another member's payload.
- Expose firstMatch, strict, and explicit raw policies while keeping typed
  sealed interfaces, record payloads, and existing root-null behavior by default.
- Count original concrete members before opaque fallbacks and decode the selected
  member once, preserving nested strict errors and authored wrapper boundaries.
- Compare exact significands and unbounded exponents instead of Gson's scale-
  limited decimal accessor, without rounding or hiding native decoder failures.
- Memoize recursive predicates by JSON node identity with qualified boxed types,
  retaining failed matches and models named Integer or Boolean without collisions.
- Preserve complete raw JSON trees, including null entries and large numbers,
  without leaking a changed null policy into ordinary sibling serialization.
- Build adapter declarations with TypeSpec and semantic fields, methods and types,
  limiting the unsupported final-class modifier escape to its single token.
- Keep ordinary and tagged codecs unchanged and exercise generated model and
  OkHttp response/error consumers through independent native policy projects.
@adamcavendish
adamcavendish force-pushed the adamcavendish/java-untagged-union-selection branch from 22a1086 to 87660a3 Compare November 11, 2026 12:51
@adamcavendish
adamcavendish merged commit 57a6eb9 into main Nov 11, 2026
31 checks passed
@adamcavendish
adamcavendish deleted the adamcavendish/java-untagged-union-selection branch November 11, 2026 13:24
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