Skip to content

feat(json): encode byte arrays as base64 JSON strings by default - #4012

Open
ingokegel wants to merge 2 commits into
apache:mainfrom
ingokegel:json_byte_array_base64
Open

feat(json): encode byte arrays as base64 JSON strings by default#4012
ingokegel wants to merge 2 commits into
apache:mainfrom
ingokegel:json_byte_array_base64

Conversation

@ingokegel

Copy link
Copy Markdown

Why?

Closes #4011.

JSON has no binary type. The ecosystem standard for byte arrays in JSON is a base64 string (see RFC 7493, the protobuf JSON mapping, Jackson, Gson, Moshi, kotlinx.serialization). Fory JSON currently writes byte[] as a JSON array of decimal numbers, which is about 2.1x larger on the wire and about 4.5x slower to write and read on binary-heavy payloads.

What does this PR do?

  • Makes Base64ByteArrayCodec the default codec for byte[], previously opt-in via @JsonBase64. The annotation still works and is now redundant.
  • Speeds up Base64 reading: a single table-driven validation scan and a table-driven quad decode replace the two-pass decode.
  • readBase64 now reserves the decoded array in the graph memory budget, like other array reads.
  • Tests updated to the base64 default

Related issues

Closes #4011

AI Contribution Checklist

  • [ no] Substantial AI assistance was used in this PR: yes / no
  • If yes, I included a completed AI Contribution Checklist in this PR description and the required AI Usage Disclosure.
  • If yes, my PR description includes the required ai_review summary and screenshot evidence or equivalent persisted links of the final clean AI review results from both fresh reviewers described in AI_POLICY.md, the Fory-guided reviewer and the independent general reviewer, on the current PR diff or current HEAD after the latest code changes.

Does this PR introduce any user-facing change?

  • Does this PR introduce any public API change?
  • [x ] Does this PR introduce any binary protocol compatibility change?

Benchmark

Round trip on a realistic payload with ~5 KB byte[] thumbnails, 2M iterations, JDK 25, Linux x86_64, project: https://github.com/ej-technologies/serialization-comparison

ns/op avg bytes
Fory JSON 1.7.0 75936 20999
this PR 16769 9742
Jackson JSON 27036 9814

JSON has no binary type, and the ecosystem standard for byte arrays in
JSON is a base64 string (RFC 7493, the protobuf JSON mapping, Jackson,
Gson, Moshi and kotlinx.serialization). The previous default wrote byte[]
as a JSON array of decimal numbers, which is several times larger on the
wire and much slower to write and parse.

The @JsonBase64 annotation already provided the base64 encoding as an
opt-in. This change makes it the default for byte[] properties, so the
annotation is no longer needed for that. Base64 reads now reserve the
decoded array in the graph memory budget, like other array reads.

BREAKING CHANGE: byte[] values are written as base64 JSON strings instead
of decimal number arrays. JSON written with earlier versions cannot be
read back with the default codec.
Base64 decoding did a branch-heavy validation scan and then a second
pass that re-read every character with per-character escape handling and
a four-way branch per digit. On binary-heavy payloads this dominated the
deserialization time.

The validation now runs as a single table-driven scan, and the decode
pass uses the same digit table without re-checking escapes. Bodies with
escaped characters fall back to the previous validating two-pass path.
@ingokegel
ingokegel requested a review from chaokunyang as a code owner August 31, 2026 16:38
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.

feat(json): byte arrays should serialize as base64 by default

1 participant