Skip to content

Backport #745 (+ follow-ups) to 2.x: Avro union resolution and schema default precision - #754

Merged
cowtowncoder merged 3 commits into
2.xfrom
tatu-claude/2.x/745-avro-union-fixes
Aug 16, 2026
Merged

Backport #745 (+ follow-ups) to 2.x: Avro union resolution and schema default precision#754
cowtowncoder merged 3 commits into
2.xfrom
tatu-claude/2.x/745-avro-union-fixes

Conversation

@cowtowncoder

@cowtowncoder cowtowncoder commented Aug 16, 2026

Copy link
Copy Markdown
Member

Backport of #745 to the 2.x line, including the follow-up fixes in #753. All four bugs are
present on 2.x unfixed.

Ported the corrected end state rather than #745 as merged, since #745 alone introduces a
BigDecimal/plain-bytes NPE that #753 fixes.

Changes

ser/AvroWriteContext.java_resolveBigDecimalIndex() tested Type.DOUBLE twice; the
first test was meant to be String/Bytes. A BigDecimal in a union was therefore always written
as double, even when a lossless branch existed. Branches are now ranked by fidelity:
decimal bytes/fixed, then String, then Double. Plain bytes/fixed are skipped —
conversion requires the logical type and would otherwise NPE.

ser/RootContext.javacreateChildObjectContext() sent every UNION to Record handling,
so a root union containing a map failed. Now resolves via _createObjectContext(), which
routes MAP to MapWriteContext.

deser/AvroFieldDefaulters.javaint and long schema defaults were built as
FloatDefaults, truncating values past float's 24-bit mantissa (2000000120000000,
9007199254740993...992).

Also re-reads type after union resolution in _createRecord(), so its error message names
the resolved type.

Three independent Avro bugs, backported from the 3.x work on #745:

* `_resolveBigDecimalIndex()` tested `Type.DOUBLE` twice (the first test
  was meant to be String/Bytes), so a `BigDecimal` in a union was always
  written as `double` even when a lossless branch existed. Rank branches
  by fidelity instead: "decimal" Bytes/Fixed, then String, then Double.
  Plain `bytes`/`fixed` are skipped, since conversion needs the logical
  type and would otherwise NPE.
* `RootContext.createChildObjectContext()` sent every UNION to Record
  handling, so a root union containing a `map` failed. Resolve via
  `_createObjectContext()`, which routes MAP to `MapWriteContext`.
* `AvroFieldDefaulters` built `FloatDefaults` for `int` and `long`
  schema defaults, truncating values past float's 24-bit mantissa.

Also re-reads `type` after union resolution in `_createRecord()`, so its
error message names the resolved type.

Test class renamed to conventional camel case, matching 3.x.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cowtowncoder cowtowncoder added this to the 2.23.0 milestone Aug 16, 2026
@cowtowncoder
cowtowncoder merged commit 882ef5b into 2.x Aug 16, 2026
3 checks passed
@cowtowncoder
cowtowncoder deleted the tatu-claude/2.x/745-avro-union-fixes branch August 16, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant