You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by ch...@apache.org on 2026/09/21 14:29:03 UTC

(fory-site) branch main updated (8de6bcc3581 -> 495a259bdd4)

This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git


    from 8de6bcc3581 🔄 synced local 'docs/json/' with remote 'docs/json/'
     new 7028e5b13ff 🔄 synced local 'docs/benchmarks/' with remote 'docs/benchmarks/'
     new 495a259bdd4 🔄 synced local 'docs/json/' with remote 'docs/json/'

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../json/byte-array-formats-results.json           | 625 +++++++++++++++++++++
 docs/benchmarks/json/byte-array-formats.md         | 105 ++++
 docs/json/annotations.md                           |  16 +-
 docs/json/graalvm.md                               |   6 +-
 docs/json/kotlin.md                                |  18 +
 docs/json/object-mapping.md                        |  50 +-
 docs/json/scala.md                                 |  19 +
 docs/json/security.md                              |   2 +-
 8 files changed, 819 insertions(+), 22 deletions(-)
 create mode 100644 docs/benchmarks/json/byte-array-formats-results.json
 create mode 100644 docs/benchmarks/json/byte-array-formats.md


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org


(fory-site) 02/02: 🔄 synced local 'docs/json/' with remote 'docs/json/'

Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git

commit 495a259bdd4363633b7bef33f584c082d29ab9bb
Author: chaokunyang <sh...@gmail.com>
AuthorDate: Mon Sep 21 14:28:58 2026 +0000

    🔄 synced local 'docs/json/' with remote 'docs/json/'
---
 docs/json/annotations.md    | 16 ++++++++++-----
 docs/json/graalvm.md        |  6 ++++--
 docs/json/kotlin.md         | 18 ++++++++++++++++
 docs/json/object-mapping.md | 50 ++++++++++++++++++++++++++++++++-------------
 docs/json/scala.md          | 19 +++++++++++++++++
 docs/json/security.md       |  2 +-
 6 files changed, 89 insertions(+), 22 deletions(-)

diff --git a/docs/json/annotations.md b/docs/json/annotations.md
index e6975f46300..be2adefc8c3 100644
--- a/docs/json/annotations.md
+++ b/docs/json/annotations.md
@@ -177,7 +177,7 @@ With an empty `items` list, this object writes `{}`. Explicit property inclusion
 class and builder defaults. Java empty-value checks run directly, even with a custom codec.
 Other types use the selected codec's `isEmpty(writer, value)`, which defaults to `false`.
 A custom codec must override it to define empty values; writing `""` or `{}` alone does not make
-an ordinary object empty. An empty `byte[]` is empty with either Base64 or numeric-array
+an ordinary object empty. An empty `byte[]` is empty with Base64, Base16, or numeric-array
 representation. See [Custom codecs](custom-codecs.md#custom-empty-values).
 
 Filtering is shallow: `0`, `false`, a list containing null, a list containing an empty list, and a
@@ -477,8 +477,8 @@ as a trusted raw root value. That combination is serialization-only: the ordinar
 
 ## `JsonByteArray`
 
-Unannotated `byte[]` values use quoted standard Base64 JSON strings. `JsonByteArray` selects
-`BASE64` or `ARRAY` for one exact `byte[]` field or getter, in both reading and writing:
+`JsonByteArray` selects `BASE64`, `BASE16`, or `ARRAY` for one exact `byte[]` field or getter, in
+both reading and writing. It overrides the builder's `byteArrayFormat`, whose default is `BASE64`:
 
 ```java
 import org.apache.fory.json.annotation.JsonByteArray;
@@ -489,10 +489,16 @@ public final class Attachment {
 
   @JsonByteArray(JsonByteArray.Format.BASE64)
   public byte[] content;
+
+  @JsonByteArray(JsonByteArray.Format.BASE16)
+  public byte[] hex;
 }
 ```
 
-For bytes `{1, -2, 3}`, `numbers` is written as `[1,-2,3]` and `content` as `"Af4D"`.
+For bytes `{1, -2, 3}`, `numbers` is written as `[1,-2,3]`, `content` as `"Af4D"`, and `hex` as
+`"01fe03"`. `BASE16` writes lowercase hexadecimal digits without a prefix or separators; it reads
+uppercase or lowercase digits, including JSON string escapes, and rejects odd-length or invalid
+hexadecimal strings.
 `ARRAY` reads JSON arrays using the signed byte range `[-128, 127]`; `BASE64` reads standard
 Base64 strings and preserves padding when writing. Each representation also accepts JSON null,
 and null output follows the property's normal inclusion rule. The default Base64 codec does not
@@ -503,7 +509,7 @@ property, not to container elements or map values. Mixin declarations can select
 It cannot share a logical property with `JsonRawValue`, an occurrence `JsonCodec`, `JsonFormat`,
 or an Any declaration. Conflicting formats on the field and getter of one property are rejected.
 
-Base64 values are binary leaves excluded from the graph-memory budget. Numeric arrays count their
+Base64 and Base16 values are binary leaves excluded from the graph-memory budget. Numeric arrays count their
 array storage against that budget; see [Security](security.md#depth-and-graph-memory-limits).
 
 ## `JsonFormat`
diff --git a/docs/json/graalvm.md b/docs/json/graalvm.md
index 22d48b3f974..7a67321e491 100644
--- a/docs/json/graalvm.md
+++ b/docs/json/graalvm.md
@@ -209,8 +209,10 @@ JVM and Android.
 
 `JsonValue` fields and effective public zero-argument methods are supported, including matching
 one-String `JsonCreator` constructors and public static factories. Fixed `JsonRawValue` fields and
-getters support trusted raw String values, and `JsonByteArray` fields and getters select Base64 strings or numeric
-byte arrays as on the JVM. `JsonFormat` date/time fields use the same direct-field,
+getters support trusted raw String values, and `JsonByteArray` fields and getters select Base64 strings,
+Base16 strings, or numeric byte arrays as on the JVM. The builder's `byteArrayFormat` controls the
+default representation; include that setting in a provider when using generated object codecs.
+`JsonFormat` date/time fields use the same direct-field,
 one-wrapper-level, and `timezone` behavior as on the JVM. For direct target annotations, annotate
 each reachable owning model with `JsonType` so Native Image retains these members and the selected byte-array
 codec constructor.
diff --git a/docs/json/kotlin.md b/docs/json/kotlin.md
index cc7a3557671..63a70d24edc 100644
--- a/docs/json/kotlin.md
+++ b/docs/json/kotlin.md
@@ -93,6 +93,24 @@ collection and map values, nullable values, Kotlin value classes backed by them,
 the Java Long-like wrappers supported by the core JSON runtime. Readers accept both quoted and
 unquoted integer tokens.
 
+`ByteArray` uses Base64 strings by default. The standard builder's `byteArrayFormat` also controls
+root arrays and arrays nested in properties, collections, and maps:
+
+```kotlin
+import org.apache.fory.json.annotation.JsonByteArray
+import org.apache.fory.json.kotlin.ForyJsonKotlin
+import org.apache.fory.json.kotlin.jsonTypeRef
+
+val hexJson = ForyJsonKotlin.builder().byteArrayFormat(JsonByteArray.Format.BASE16).build()
+val bytesType = jsonTypeRef<ByteArray>()
+val text = hexJson.toJson(byteArrayOf(1, -2, 3), bytesType) // "\"01fe03\""
+val bytes = hexJson.fromJson(text, bytesType)
+```
+
+`@field:JsonByteArray` or `@get:JsonByteArray`, including a Mixin declaration, overrides the default
+for that property. `UByteArray` retains its unsigned numeric-array representation. See
+[byte-array formats](object-mapping.md#builder-configuration) for accepted input and null behavior.
+
 `jsonTypeRef<T>()` is a type token, not a codec lookup. Construct it once and reuse it. A Java
 `Class` or ordinary Java `TypeRef` cannot express distinctions such as `List<Account?>`, `UInt`, or
 a logical value class lowered to a primitive carrier.
diff --git a/docs/json/object-mapping.md b/docs/json/object-mapping.md
index 63382d318dd..4cd8a405d1c 100644
--- a/docs/json/object-mapping.md
+++ b/docs/json/object-mapping.md
@@ -229,20 +229,42 @@ for supported sources, construction/evaluation effects, and errors. An explicit
 overrides `JsonInclude` on the class, which overrides the builder default. See
 [Property inclusion](annotations.md#jsonproperty) for the empty-value definitions and boundaries.
 
-| Builder method                         | Default                                   | User-visible effect                                        |
-| -------------------------------------- | ----------------------------------------- | ---------------------------------------------------------- |
-| `defaultPropertyInclusion(Include)`    | `NON_NULL`                                | Default inclusion of object properties                     |
-| `writeNullFields(boolean)`             | `false`                                   | Select `ALWAYS` when true or `NON_NULL` when false         |
-| `writeLongAsString(boolean)`           | `false`                                   | Write built-in 64-bit integer values as decimal strings    |
-| `withCodegen(boolean)`                 | `true`                                    | Enable generated object codecs                             |
-| `withAsyncCompilation(boolean)`        | `true`                                    | Compile generated codecs asynchronously                    |
-| `withFieldMode(boolean)`               | `false`                                   | When true, discover fields without getters/setters         |
-| `withPropertyNamingStrategy(strategy)` | `LOWER_CAMEL_CASE`                        | Name properties without an explicit `JsonProperty` name    |
-| `withMaxCachedFieldNames(int)`         | `DEFAULT_MAX_CACHED_FIELD_NAMES` (`8192`) | Field-name cache entries per reader; zero disables caching |
-| `withConcurrencyLevel(int)`            | `max(1, 2 * processors)`                  | Maximum concurrent root operations                         |
-| `withBufferSizeLimitBytes(int)`        | 2 MiB                                     | Maximum retained output/string-decoding buffer capacity    |
-| `registerCodec(type, codec)`           | None                                      | Replace an eligible exact class's complete JSON codec      |
-| `registerMixin(mixinType)`             | None                                      | Apply one annotation Mixin to its exact declared target    |
+| Builder method                          | Default                                   | User-visible effect                                        |
+| --------------------------------------- | ----------------------------------------- | ---------------------------------------------------------- |
+| `defaultPropertyInclusion(Include)`     | `NON_NULL`                                | Default inclusion of object properties                     |
+| `writeNullFields(boolean)`              | `false`                                   | Select `ALWAYS` when true or `NON_NULL` when false         |
+| `writeLongAsString(boolean)`            | `false`                                   | Write built-in 64-bit integer values as decimal strings    |
+| `byteArrayFormat(JsonByteArray.Format)` | `BASE64`                                  | Default byte-array representation for reading and writing  |
+| `withCodegen(boolean)`                  | `true`                                    | Enable generated object codecs                             |
+| `withAsyncCompilation(boolean)`         | `true`                                    | Compile generated codecs asynchronously                    |
+| `withFieldMode(boolean)`                | `false`                                   | When true, discover fields without getters/setters         |
+| `withPropertyNamingStrategy(strategy)`  | `LOWER_CAMEL_CASE`                        | Name properties without an explicit `JsonProperty` name    |
+| `withMaxCachedFieldNames(int)`          | `DEFAULT_MAX_CACHED_FIELD_NAMES` (`8192`) | Field-name cache entries per reader; zero disables caching |
+| `withConcurrencyLevel(int)`             | `max(1, 2 * processors)`                  | Maximum concurrent root operations                         |
+| `withBufferSizeLimitBytes(int)`         | 2 MiB                                     | Maximum retained output/string-decoding buffer capacity    |
+| `registerCodec(type, codec)`            | None                                      | Replace an eligible exact class's complete JSON codec      |
+| `registerMixin(mixinType)`              | None                                      | Apply one annotation Mixin to its exact declared target    |
+
+Use `byteArrayFormat` to choose one representation for ordinary `byte[]` roots, unannotated
+properties, and container values, including nested arrays, collections, maps, and optionals:
+
+```java
+import org.apache.fory.json.ForyJson;
+import org.apache.fory.json.annotation.JsonByteArray;
+
+ForyJson hexJson = ForyJson.builder().byteArrayFormat(JsonByteArray.Format.BASE16).build();
+String text = hexJson.toJson(new byte[] {1, -2, 3}); // "\"01fe03\""
+byte[] bytes = hexJson.fromJson(text, byte[].class);
+```
+
+`BASE64` is the default and writes padded standard Base64 strings. `BASE16` writes lowercase
+hexadecimal strings without prefixes or separators; reading accepts either case and JSON string
+escapes. Odd-length strings and non-hexadecimal characters are rejected. `ARRAY` uses signed
+numbers in `[-128, 127]`. Empty arrays become `""` for either string format or `[]` for `ARRAY`.
+All three formats accept JSON `null`. The reader uses the configured representation and does not
+guess another format. A [property's `JsonByteArray` annotation](annotations.md#jsonbytearray),
+including one supplied by a Mixin, overrides the global default. Custom occurrence codecs retain
+their complete representation; Kotlin unsigned semantic arrays remain numeric arrays.
 
 Enable `writeLongAsString(true)` when 64-bit integer values must pass through JavaScript without
 `Number` precision loss. The setting writes built-in `long`/`Long`, `AtomicLong`,
diff --git a/docs/json/scala.md b/docs/json/scala.md
index 2054d0ec936..2f31e3efb36 100644
--- a/docs/json/scala.md
+++ b/docs/json/scala.md
@@ -47,6 +47,25 @@ wrappers as quoted decimal strings. Readers accept both quoted and unquoted inte
 Use `ScalaTypeRef` when a parameterized declaration contains `Long` because normal JVM signatures
 can erase Scala value-type arguments to `Object`.
 
+## Byte-array formats
+
+Scala `Array[Byte]` uses Base64 strings by default. Use the standard builder's
+`byteArrayFormat` to select numeric arrays or hexadecimal strings, including arrays inside
+`Option`, Scala collections, and maps:
+
+```scala
+import org.apache.fory.json.annotation.JsonByteArray
+import org.apache.fory.json.scala.{ForyJsonScala, ScalaTypeRef}
+
+val hexJson = ForyJsonScala.builder().byteArrayFormat(JsonByteArray.Format.BASE16).build()
+val bytesType = ScalaTypeRef[Array[Byte]]
+val text = hexJson.toJson(Array[Byte](1, -2, 3), bytesType) // "\"01fe03\""
+val bytes = hexJson.fromJson(text, bytesType)
+```
+
+`JsonByteArray` on a field or getter, including a Mixin, overrides the default for that property.
+See [byte-array formats](object-mapping.md#builder-configuration) for the read/write contract.
+
 ## Case classes and annotations
 
 Case classes are decoded by calling their full primary constructor. Fory invokes Scala's generated
diff --git a/docs/json/security.md b/docs/json/security.md
index deecb49d45b..3de92c2f6c8 100644
--- a/docs/json/security.md
+++ b/docs/json/security.md
@@ -101,7 +101,7 @@ is also charged once; a cached empty Optional singleton is not a new graph owner
 Dedicated leaf codecs are excluded from graph accounting: null, strings,
 characters, booleans, numeric values including arbitrary-precision numbers,
 enums, temporal and other scalar values, and binary values. A `byte[]` handled
-by a binary or Base64 codec remains a binary leaf; the same Java carrier read
+by a Base64 or Base16 codec remains a binary leaf; the same Java carrier read
 from a JSON numeric array is a primitive-array owner. Byte-availability and
 grammar checks still apply independently of graph accounting.
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org


(fory-site) 01/02: 🔄 synced local 'docs/benchmarks/' with remote 'docs/benchmarks/'

Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git

commit 7028e5b13ff09aad9851380f8080cdf1fa0d7c89
Author: chaokunyang <sh...@gmail.com>
AuthorDate: Mon Sep 21 14:28:58 2026 +0000

    🔄 synced local 'docs/benchmarks/' with remote 'docs/benchmarks/'
---
 .../json/byte-array-formats-results.json           | 625 +++++++++++++++++++++
 docs/benchmarks/json/byte-array-formats.md         | 105 ++++
 2 files changed, 730 insertions(+)

diff --git a/docs/benchmarks/json/byte-array-formats-results.json b/docs/benchmarks/json/byte-array-formats-results.json
new file mode 100644
index 00000000000..ca2f84727dd
--- /dev/null
+++ b/docs/benchmarks/json/byte-array-formats-results.json
@@ -0,0 +1,625 @@
+{
+  "environment": {
+    "cpu": "Apple M4 Pro",
+    "logical_cpus": 12,
+    "os": "macOS 15.7.2 arm64",
+    "jdk": "OpenJDK 25.0.3",
+    "jmh": "1.37"
+  },
+  "source": {
+    "fory": "13739263ebf31af5fc962184aaccf2833f8ffc9a",
+    "fory_baseline": "e1d2f9d67800901392755b1133968d448ab076b8",
+    "jsoniter_scala_base": "84cb277f2c2a16b4018bc61fdeec3eed62252a1e",
+    "jsoniter_scala_adapters": "71b2ba16f1d5261e2be4e98d5dfe4be452d0e136",
+    "jsoniter_scala_version": "2.40.2-SNAPSHOT",
+    "benchmark_scala": "3.9.0",
+    "fory_scala": "3.3.8"
+  },
+  "settings": {
+    "threads": 1,
+    "forks_per_run": 1,
+    "warmup_iterations": 3,
+    "measurement_iterations": 5,
+    "iteration_seconds": 1,
+    "jvm_args": ["-Xms1g", "-Xmx1g", "-XX:+UseParallelGC"],
+    "profiler": "gc"
+  },
+  "results": [
+    {
+      "case": "ArrayOfBytesReading",
+      "size": 512,
+      "pairs": [
+        {
+          "pair": 1,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 718561.6343142863,
+            "iterations_ops_s": [
+              720966.2774700475, 722148.059950197, 723968.2127171038,
+              699675.4454108089, 726050.1760232744
+            ],
+            "allocation_bytes_op": 528.0081562652304,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 644154.4427726491,
+            "iterations_ops_s": [
+              642739.6225877892, 656549.9366009792, 647274.0194844017,
+              629323.8870815604, 644884.7481085152
+            ],
+            "allocation_bytes_op": 1128.0091134734967,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.1155114155874863
+        },
+        {
+          "pair": 2,
+          "order": ["fory", "jsoniter_scala"],
+          "fory": {
+            "throughput_ops_s": 712768.7484642493,
+            "iterations_ops_s": [
+              715809.6255148505, 712322.2180004838, 719427.3859759014,
+              706451.1582493099, 709833.3545807011
+            ],
+            "allocation_bytes_op": 528.0082231131366,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 646910.5376279108,
+            "iterations_ops_s": [
+              653642.6650007655, 648076.5626362266, 639063.9666087512,
+              648406.7871787745, 645362.7067150369
+            ],
+            "allocation_bytes_op": 1128.0090703040241,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.1018042016718836
+        },
+        {
+          "pair": 3,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 713855.8384418925,
+            "iterations_ops_s": [
+              713930.6941047948, 699719.8311706063, 713989.776513808,
+              721117.7876197997, 720521.1028004538
+            ],
+            "allocation_bytes_op": 528.0082200551103,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 648694.3313125791,
+            "iterations_ops_s": [
+              640046.1536157951, 651947.475615739, 650393.8228952556,
+              649302.6479094238, 651781.5565266822
+            ],
+            "allocation_bytes_op": 1128.0090437194845,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.100450249037115
+        }
+      ],
+      "median_fory_ops_s": 713855.8384418925,
+      "median_jsoniter_ops_s": 646910.5376279108,
+      "median_paired_ratio": 1.1018042016718836,
+      "minimum_paired_ratio": 1.100450249037115,
+      "maximum_paired_ratio": 1.1155114155874863,
+      "geometric_paired_ratio": 1.1059010882137206
+    },
+    {
+      "case": "ArrayOfBytesWriting",
+      "size": 512,
+      "pairs": [
+        {
+          "pair": 1,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 3350580.997475249,
+            "iterations_ops_s": [
+              3354256.676965812, 3350235.8910908336, 3370583.284923328,
+              3343149.3809342943, 3334679.7534619793
+            ],
+            "allocation_bytes_op": 1888.0017545395815,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 1534400.3964775414,
+            "iterations_ops_s": [
+              1555002.3973013056, 1551437.3792732242, 1483784.9963905278,
+              1539026.116856106, 1542751.092566543
+            ],
+            "allocation_bytes_op": 1888.003826423861,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 2.1836419002282828
+        },
+        {
+          "pair": 2,
+          "order": ["fory", "jsoniter_scala"],
+          "fory": {
+            "throughput_ops_s": 3355366.2425028966,
+            "iterations_ops_s": [
+              3371208.1427841824, 3370052.5561299818, 3367852.548591301,
+              3335320.999305273, 3332396.965703745
+            ],
+            "allocation_bytes_op": 1888.0017485208652,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 1539684.6759449516,
+            "iterations_ops_s": [
+              1530588.7989645593, 1536345.1128779924, 1550446.53671775,
+              1520990.2236222902, 1560052.7075421656
+            ],
+            "allocation_bytes_op": 1888.0038163834627,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 2.179255463748514
+        },
+        {
+          "pair": 3,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 3328563.302552803,
+            "iterations_ops_s": [
+              3320520.682048541, 3331924.359155337, 3319451.2998794424,
+              3332810.7688661655, 3338109.40281453
+            ],
+            "allocation_bytes_op": 1888.0017662799612,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 1540486.9964760381,
+            "iterations_ops_s": [
+              1537960.3534940826, 1560478.5204790654, 1537766.2635790894,
+              1527368.4693392226, 1538861.3754887313
+            ],
+            "allocation_bytes_op": 1888.0038109181107,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 2.1607214537786446
+        }
+      ],
+      "median_fory_ops_s": 3350580.997475249,
+      "median_jsoniter_ops_s": 1539684.6759449516,
+      "median_paired_ratio": 2.179255463748514,
+      "minimum_paired_ratio": 2.1607214537786446,
+      "maximum_paired_ratio": 2.1836419002282828,
+      "geometric_paired_ratio": 2.174516874590141
+    },
+    {
+      "case": "Base16Reading",
+      "size": 512,
+      "pairs": [
+        {
+          "pair": 1,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 3359808.747011424,
+            "iterations_ops_s": [
+              3170890.4021431804, 2835783.848635741, 3599267.745232154,
+              3600313.8419093373, 3592787.8971367073
+            ],
+            "allocation_bytes_op": 528.0017648087484,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 2914929.3631949537,
+            "iterations_ops_s": [
+              2894217.0461341827, 2909705.468348089, 2928398.5845325943,
+              2897313.7225826643, 2945011.9943772373
+            ],
+            "allocation_bytes_op": 528.0020149494615,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.1526209826672622
+        },
+        {
+          "pair": 2,
+          "order": ["fory", "jsoniter_scala"],
+          "fory": {
+            "throughput_ops_s": 3585325.1970511647,
+            "iterations_ops_s": [
+              3606779.6047478, 3620212.096465545, 3585192.9164911993,
+              3573313.8467803146, 3541127.5207709647
+            ],
+            "allocation_bytes_op": 528.0016362855811,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 2873552.418737786,
+            "iterations_ops_s": [
+              2761830.775159276, 2916270.0082977437, 2909785.4844934223,
+              2912280.347573207, 2867595.47816528
+            ],
+            "allocation_bytes_op": 528.0020441965414,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.2476978577707751
+        },
+        {
+          "pair": 3,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 3603439.30158346,
+            "iterations_ops_s": [
+              3626219.544144616, 3602839.8185009575, 3602282.722974174,
+              3598315.7871311214, 3587538.6351664294
+            ],
+            "allocation_bytes_op": 528.0016283749771,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 2949382.2375222584,
+            "iterations_ops_s": [
+              2947324.1011699555, 2941788.9030553037, 2943400.2053664513,
+              2947093.167103884, 2967304.8109156964
+            ],
+            "allocation_bytes_op": 528.001988912211,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.2217606981354399
+        }
+      ],
+      "median_fory_ops_s": 3585325.1970511647,
+      "median_jsoniter_ops_s": 2914929.3631949537,
+      "median_paired_ratio": 1.2217606981354399,
+      "minimum_paired_ratio": 1.1526209826672622,
+      "maximum_paired_ratio": 1.2476978577707751,
+      "geometric_paired_ratio": 1.2066853323390903
+    },
+    {
+      "case": "Base16Writing",
+      "size": 512,
+      "pairs": [
+        {
+          "pair": 1,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 9639285.749072284,
+            "iterations_ops_s": [
+              9720176.667163966, 9484401.322246242, 9672723.887067826,
+              9634169.371241517, 9684957.497641867
+            ],
+            "allocation_bytes_op": 1048.0006091523976,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 8472009.567249341,
+            "iterations_ops_s": [
+              8479680.230866075, 8457165.337729625, 8507324.055039847,
+              8446205.415500265, 8469672.797110893
+            ],
+            "allocation_bytes_op": 1048.0006932682013,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.137780319127039
+        },
+        {
+          "pair": 2,
+          "order": ["fory", "jsoniter_scala"],
+          "fory": {
+            "throughput_ops_s": 9790192.385472855,
+            "iterations_ops_s": [
+              9729910.203410858, 9798489.073830001, 9801086.328943448,
+              9821711.761606097, 9799764.559573878
+            ],
+            "allocation_bytes_op": 1048.0005986565332,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 8444372.230910677,
+            "iterations_ops_s": [
+              8454419.247091914, 8498853.198057437, 8439041.593527095,
+              8413092.78031926, 8416454.335557679
+            ],
+            "allocation_bytes_op": 1048.0006945067705,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.159374802266034
+        },
+        {
+          "pair": 3,
+          "order": ["jsoniter_scala", "fory"],
+          "fory": {
+            "throughput_ops_s": 9627140.75202604,
+            "iterations_ops_s": [
+              9571136.694928922, 9670291.685970405, 9650637.061303275,
+              9649359.818529114, 9594278.499398485
+            ],
+            "allocation_bytes_op": 1048.0006093169627,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "jsoniter_scala": {
+            "throughput_ops_s": 8299340.122327629,
+            "iterations_ops_s": [
+              8304739.0318363365, 8098181.555887745, 8329959.2642635,
+              8378818.139460061, 8385002.620190503
+            ],
+            "allocation_bytes_op": 1048.0007070897,
+            "artifact_sha256": {
+              "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+              "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+              "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+              "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+            }
+          },
+          "throughput_ratio": 1.1599886991167216
+        }
+      ],
+      "median_fory_ops_s": 9639285.749072284,
+      "median_jsoniter_ops_s": 8444372.230910677,
+      "median_paired_ratio": 1.159374802266034,
+      "minimum_paired_ratio": 1.137780319127039,
+      "maximum_paired_ratio": 1.1599886991167216,
+      "geometric_paired_ratio": 1.1523347999694993
+    }
+  ],
+  "numeric_read_development_pairs": [
+    {
+      "pair": 1,
+      "measurement_iterations": 3,
+      "baseline": {
+        "throughput_ops_s": 532673.8573387515,
+        "iterations_ops_s": [
+          525513.9417793049, 542316.8084152596, 530190.8218216901
+        ],
+        "allocation_bytes_op": 1656.0110539563302,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "fory": {
+        "throughput_ops_s": 688445.4281281951,
+        "iterations_ops_s": [
+          661077.1182975627, 700984.16167637, 703275.0044106527
+        ],
+        "allocation_bytes_op": 528.0085360717871,
+        "artifact_sha256": {
+          "fory_json": "3dc8c8cce674855b39faca03156bf57048bb28d1503513cd5d5a85c6935ea696",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "jsoniter_scala": {
+        "throughput_ops_s": 633958.6015719158,
+        "iterations_ops_s": [
+          617689.5090250478, 649548.5363109286, 634637.7593797712
+        ],
+        "allocation_bytes_op": 1128.0092592375615,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      }
+    },
+    {
+      "pair": 2,
+      "measurement_iterations": 3,
+      "baseline": {
+        "throughput_ops_s": 540338.0918875013,
+        "iterations_ops_s": [
+          536275.7264876695, 526926.7419483826, 557811.8072264518
+        ],
+        "allocation_bytes_op": 1656.0108723773349,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "fory": {
+        "throughput_ops_s": 720624.0504748118,
+        "iterations_ops_s": [
+          725308.188246871, 717928.044117385, 718635.9190601795
+        ],
+        "allocation_bytes_op": 528.0081332921432,
+        "artifact_sha256": {
+          "fory_json": "3dc8c8cce674855b39faca03156bf57048bb28d1503513cd5d5a85c6935ea696",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "jsoniter_scala": {
+        "throughput_ops_s": 637647.9827981751,
+        "iterations_ops_s": [
+          633147.7919315896, 637860.5415264402, 641935.6149364957
+        ],
+        "allocation_bytes_op": 1128.0092273109979,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      }
+    }
+  ],
+  "integer_read_control": [
+    {
+      "pair": 1,
+      "baseline": {
+        "throughput_ops_s": 491577.15519360424,
+        "iterations_ops_s": [
+          493226.1424904787, 487426.7022866886, 491108.85466615774,
+          489525.76150114706, 496598.3150235495
+        ],
+        "allocation_bytes_op": 4176.011942924268,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "fory": {
+        "throughput_ops_s": 498496.5149580714,
+        "iterations_ops_s": [
+          500744.575380113, 500638.4030852225, 493489.2902459867,
+          498268.2111324434, 499342.09494659153
+        ],
+        "allocation_bytes_op": 4176.011777540917,
+        "artifact_sha256": {
+          "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      }
+    },
+    {
+      "pair": 2,
+      "baseline": {
+        "throughput_ops_s": 487399.4866039612,
+        "iterations_ops_s": [
+          492882.917488924, 491449.6032085084, 492271.10849723214,
+          483111.02830760553, 477282.77551753627
+        ],
+        "allocation_bytes_op": 4176.012066509457,
+        "artifact_sha256": {
+          "fory_json": "0b175646200572bd67817e5ff6350ca9b41ecf8d9c5fedb46ef90677fe335014",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      },
+      "fory": {
+        "throughput_ops_s": 492338.3696801558,
+        "iterations_ops_s": [
+          482311.38343038387, 493766.54553907254, 493700.9130787423,
+          495583.89678214624, 496329.1095704343
+        ],
+        "allocation_bytes_op": 4176.01193743859,
+        "artifact_sha256": {
+          "fory_json": "a60312c784247481c49a6a7a2bf128979fdba070c305a0e1f95966673237883b",
+          "fory_scala": "69bce71e74891f86f0a2b1a607b2a86743955e5378386dbc3ab72e64c30f62cd",
+          "fory_core": "1d743236d0529f1e0c082bba9abc36bf502167add84905441ad917f7143b5b9a",
+          "benchmark": "606d03f7f6fb4bbf217b3e2d30ae82054d702aa937148328b1987191bd63e3b4"
+        }
+      }
+    }
+  ]
+}
diff --git a/docs/benchmarks/json/byte-array-formats.md b/docs/benchmarks/json/byte-array-formats.md
new file mode 100644
index 00000000000..51b915f1c3d
--- /dev/null
+++ b/docs/benchmarks/json/byte-array-formats.md
@@ -0,0 +1,105 @@
+# JVM JSON byte-array format measurements
+
+This comparison covers numeric byte arrays and Base16 strings on the unchanged
+jsoniter-scala `ArrayOfBytesReading`, `ArrayOfBytesWriting`, `Base16Reading`, and
+`Base16Writing` workloads at `size=512`. Higher throughput is better.
+
+All 12 final adjacent comparison pairs exceed 10%. Numeric-array reading has a
+narrow margin: its smallest measured improvement is 10.05%. These are local
+steady-state measurements, not a guarantee for other sizes, data distributions,
+machines, or JVMs.
+
+## Results
+
+| Workload                   | jsoniter-scala median, ops/s | Fory median, ops/s | Median paired improvement |         Paired range |
+| -------------------------- | ---------------------------: | -----------------: | ------------------------: | -------------------: |
+| Numeric byte-array reading |                      646,911 |            713,856 |                   +10.18% |   +10.05% to +11.55% |
+| Numeric byte-array writing |                    1,539,685 |          3,350,581 |                  +117.93% | +116.07% to +118.36% |
+| Base16 reading             |                    2,914,929 |          3,585,325 |                   +22.18% |   +15.26% to +24.77% |
+| Base16 writing             |                    8,444,372 |          9,639,286 |                   +15.94% |   +13.78% to +16.00% |
+
+Each pair compares the means of five measurement iterations. The improvement
+column is the median of those paired ratios, not the ratio of independent medians.
+All final samples are retained. Earlier, shorter numeric-reading comparisons
+measured +8.59% and +13.01%; they are also included in the evidence and illustrate
+why the final narrow margin should not be generalized.
+
+Allocation per operation is approximately 528 B for Fory numeric-array reading
+and 1,128 B for jsoniter-scala. Both libraries allocate about 1,888 B for numeric
+array output, 528 B for Base16 input, and 1,048 B for Base16 output. Both use APIs
+that return independent arrays; neither uses the preallocated-output benchmark.
+Startup and retained lookup-table memory are outside these steady-state allocation
+figures. Fory's Base16 output table occupies 256 KiB after its first use.
+
+The affected integer-reading path was also compared with the pre-optimization
+Fory revision in two adjacent pairs. Changes were +1.41% and +1.01%, within the
+range normally treated as noise; no regression was observed in those runs.
+
+[Iteration samples, allocations, paired results, and artifact hashes](byte-array-formats-results.json)
+are available as JSON.
+
+## Workloads and configuration
+
+The input bytes are the benchmark's original sequence
+`(1 to size).map(_.toByte).toArray`. Numeric arrays keep the original signed decimal
+JSON representation. Base16 keeps the original lowercase hexadecimal string.
+Models, inputs, expected outputs, and jsoniter-scala implementations are unchanged.
+Only the missing Fory adapters and their existing correctness specs are enabled.
+
+Fory uses separate instances configured through its public builder:
+
+```java
+import org.apache.fory.json.ForyJson;
+import org.apache.fory.json.annotation.JsonByteArray;
+
+ForyJson arrays = ForyJson.builder().byteArrayFormat(JsonByteArray.Format.ARRAY).build();
+ForyJson hex = ForyJson.builder().byteArrayFormat(JsonByteArray.Format.BASE16).build();
+```
+
+Each reading adapter calls `fromJson(jsonBytes, classOf[Array[Byte]])`; each writing
+adapter calls `toJsonBytes(obj)`. These configurations also apply to nested byte
+arrays; they are not benchmark-specific codecs.
+
+## Environment and revisions
+
+- Date: September 21, 2026.
+- Apple M4 Pro, 12 logical CPUs, 48 GiB RAM; macOS 15.7.2 arm64.
+- OpenJDK 25.0.3; JMH 1.37.
+- Fory: `13739263ebf31af5fc962184aaccf2833f8ffc9a`, version `1.8.0-SNAPSHOT`.
+- Fory pre-optimization baseline: `e1d2f9d67800901392755b1133968d448ab076b8`.
+- jsoniter-scala: `2.40.2-SNAPSHOT`, checkout
+  `71b2ba16f1d5261e2be4e98d5dfe4be452d0e136`; its Fory adapter additions are based on
+  `84cb277f2c2a16b4018bc61fdeec3eed62252a1e`.
+- Benchmark Scala: 3.9.0; Fory JSON Scala: 3.3.8.
+- One thread and one fork per run; three 1-second warmups and five 1-second
+  measurements; `-Xms1g -Xmx1g -XX:+UseParallelGC`; JMH GC profiler.
+- Three adjacent pairs per workload. Order is jsoniter/Fory, Fory/jsoniter,
+  jsoniter/Fory. Runs are serial; normal desktop background activity remains.
+
+The runtime, core, Scala, and benchmark jars are frozen during measurement. Only
+the Fory JSON runtime jar changes in baseline/current controls.
+
+## Reproduction
+
+Install Fory core, JSON, and JSON Scala artifacts before building the benchmark
+assembly. Enable Maven Local when using locally published snapshots:
+
+```bash
+sbt --java-home "$JAVA_HOME" \
+  'set ThisBuild / resolvers += Resolver.mavenLocal' \
+  '++3.9.0!' 'jsoniter-scala-benchmarkJVM/assembly'
+```
+
+Run each method as a separate process, alternating the library order between
+pairs. Use the same frozen classpath for both methods:
+
+```bash
+java -cp "$FORY_JSON_JAR:$FORY_SCALA_JAR:$FORY_CORE_JAR:$BENCHMARK_JAR" \
+  org.openjdk.jmh.Main ".*\.${CASE}\.${METHOD}$" \
+  -t 1 -f 1 -wi 3 -i 5 -w 1s -r 1s -p size=512 \
+  -jvmArgs '-Xms1g -Xmx1g -XX:+UseParallelGC' -foe true -prof gc \
+  -rf json -rff "$RESULT_FILE"
+```
+
+`CASE` is one of the four workload names above; `METHOD` is `fory` or
+`jsoniterScala`. No GraalVM or native-image performance is measured here.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org