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
The following commit(s) were added to refs/heads/main by this push:
new 6e76d05cf π synced local 'docs/docs/guide/' with remote 'docs/guide/'
6e76d05cf is described below
commit 6e76d05cf2675636e454f106cdb5a3ce77a4cade
Author: chaokunyang <[email protected]>
AuthorDate: Thu Dec 11 02:28:42 2025 +0000
π synced local 'docs/docs/guide/' with remote 'docs/guide/'
---
docs/docs/guide/cpp/index.md | 2 +-
docs/docs/guide/java/index.md | 28 ++
docs/docs/guide/kotlin/default-values.md | 137 ++++++
docs/docs/guide/kotlin/fory-creation.md | 116 +++++
docs/docs/guide/kotlin/index.md | 92 +++-
docs/docs/guide/kotlin/type-serialization.md | 184 ++++++++
docs/docs/guide/rust/index.md | 2 +-
docs/docs/guide/rust_guide.md | 2 +-
docs/docs/guide/scala/default-values.md | 186 ++++++++
docs/docs/guide/scala/fory-creation.md | 139 ++++++
docs/docs/guide/scala/index.md | 82 +++-
docs/docs/guide/scala/type-serialization.md | 171 ++++++++
docs/docs/guide/xlang/row_format.md | 205 +++++++++
docs/docs/guide/xlang/serialization.md | 610 +++++++++++++++++++++++++++
14 files changed, 1950 insertions(+), 6 deletions(-)
diff --git a/docs/docs/guide/cpp/index.md b/docs/docs/guide/cpp/index.md
index 19c40d992..e31b99244 100644
--- a/docs/docs/guide/cpp/index.md
+++ b/docs/docs/guide/cpp/index.md
@@ -30,7 +30,7 @@ The C++ implementation provides high-performance
serialization with compile-time
- **π― Type-Safe**: Compile-time type checking with macro-based struct
registration
- **π Reference Tracking**: Automatic tracking of shared and circular
references
- **π¦ Schema Evolution**: Compatible mode for independent schema changes
-- **β‘ Two Modes**: Object graph serialization and zero-copy row-based format
+- **β‘ Two Formats**: Object graph serialization and zero-copy row-based format
- **π§΅ Thread Safety**: Both single-threaded (fastest) and thread-safe variants
## Installation
diff --git a/docs/docs/guide/java/index.md b/docs/docs/guide/java/index.md
index e7c05a69d..eeecad2fc 100644
--- a/docs/docs/guide/java/index.md
+++ b/docs/docs/guide/java/index.md
@@ -21,6 +21,34 @@ license: |
Apache Foryβ’ provides blazingly fast Java object serialization with JIT
compilation and zero-copy techniques. When only Java object serialization is
needed, this mode delivers better performance compared to cross-language object
graph serialization.
+## Features
+
+### High Performance
+
+- **JIT Code Generation**: Highly-extensible JIT framework generates
serializer code at runtime using async multi-threaded compilation, delivering
20-170x speedup through:
+ - Inlining variables to reduce memory access
+ - Inlining method calls to eliminate virtual dispatch overhead
+ - Minimizing conditional branching
+ - Eliminating hash lookups
+- **Zero-Copy**: Direct memory access without intermediate buffer copies; row
format supports random access and partial serialization
+- **Variable-Length Encoding**: Optimized compression for integers, longs
+- **Meta Sharing**: Cached class metadata reduces redundant type information
+- **SIMD Acceleration**: Java Vector API support for array operations (Java
16+)
+
+### Drop-in Replacement
+
+- **100% JDK Serialization Compatible**: Supports
`writeObject`/`readObject`/`writeReplace`/`readResolve`/`readObjectNoData`/`Externalizable`
+- **Java 8-24 Support**: Works across all modern Java versions including Java
17+ records
+- **GraalVM Native Image**: AOT compilation support without reflection
configuration
+
+### Advanced Features
+
+- **Reference Tracking**: Automatic handling of shared and circular references
+- **Schema Evolution**: Forward/backward compatibility for class schema changes
+- **Polymorphism**: Full support for inheritance hierarchies and interfaces
+- **Deep Copy**: Efficient deep cloning of complex object graphs with
reference preservation
+- **Security**: Class registration and configurable deserialization policies
+
## Quick Start
Note that Fory creation is not cheap, the **Fory instances should be reused
between serializations** instead of creating it every time. You should keep
Fory as a static global variable, or instance variable of some singleton object
or limited objects.
diff --git a/docs/docs/guide/kotlin/default-values.md
b/docs/docs/guide/kotlin/default-values.md
new file mode 100644
index 000000000..76c1882a6
--- /dev/null
+++ b/docs/docs/guide/kotlin/default-values.md
@@ -0,0 +1,137 @@
+---
+title: Default Values
+sidebar_position: 3
+id: kotlin_default_values
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory supports Kotlin data class default values during deserialization when
using compatible mode. This feature enables forward/backward compatibility when
data class schemas evolve.
+
+## Overview
+
+When a Kotlin data class has parameters with default values, Fory can:
+
+1. **Detect default values** using Kotlin reflection
+2. **Apply default values** during deserialization when fields are missing
from serialized data
+3. **Support schema evolution** by allowing new fields with defaults to be
added without breaking existing serialized data
+
+## Usage
+
+This feature is automatically enabled when:
+
+- Compatible mode is enabled (`withCompatibleMode(CompatibleMode.COMPATIBLE)`)
+- Kotlin serializers are registered
(`KotlinSerializers.registerSerializers(fory)`)
+- A field is missing from the serialized data but exists in the target class
with a default value
+
+## Example
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.config.CompatibleMode
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+// Original data class
+data class User(val name: String, val age: Int)
+
+// Evolved data class with new field and default value
+data class UserV2(val name: String, val age: Int, val email: String =
"[email protected]")
+
+fun main() {
+ val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .build()
+ KotlinSerializers.registerSerializers(fory)
+ fory.register(User::class.java)
+ fory.register(UserV2::class.java)
+
+ // Serialize with old schema
+ val oldUser = User("John", 30)
+ val serialized = fory.serialize(oldUser)
+
+ // Deserialize with new schema - missing field gets default value
+ val newUser = fory.deserialize(serialized) as UserV2
+ println(newUser) // UserV2(name=John, age=30, [email protected])
+}
+```
+
+## Supported Default Value Types
+
+The following types are supported for default values:
+
+- **Primitive types**: `Int`, `Long`, `Double`, `Float`, `Boolean`, `Byte`,
`Short`, `Char`
+- **Unsigned types**: `UInt`, `ULong`, `UByte`, `UShort`
+- **String**: `String`
+- **Collections**: `List`, `Set`, `Map` (with default instances)
+- **Custom objects**: Any object that can be instantiated via reflection
+
+## Complex Default Values
+
+Default values can be complex expressions:
+
+```kotlin
+data class ConfigV1(val name: String)
+
+data class ConfigV2(
+ val name: String,
+ val settings: Map<String, String> = mapOf("default" to "value"),
+ val tags: List<String> = listOf("default"),
+ val enabled: Boolean = true,
+ val retryCount: Int = 3
+)
+
+val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .build()
+KotlinSerializers.registerSerializers(fory)
+
+val original = ConfigV1("myConfig")
+val serialized = fory.serialize(original)
+
+val deserialized = fory.deserialize(serialized) as ConfigV2
+// deserialized.name == "myConfig"
+// deserialized.settings == mapOf("default" to "value")
+// deserialized.tags == listOf("default")
+// deserialized.enabled == true
+// deserialized.retryCount == 3
+```
+
+## Nullable Fields with Defaults
+
+Nullable fields with default values are also supported:
+
+```kotlin
+data class PersonV1(val name: String)
+
+data class PersonV2(
+ val name: String,
+ val nickname: String? = null,
+ val age: Int? = null
+)
+
+val original = PersonV1("John")
+val serialized = fory.serialize(original)
+
+val deserialized = fory.deserialize(serialized) as PersonV2
+// deserialized.name == "John"
+// deserialized.nickname == null (default)
+// deserialized.age == null (default)
+```
+
+## Related Topics
+
+- [Schema Evolution](../java/schema-evolution.md) - Forward/backward
compatibility in Java
+- [Fory Creation](fory-creation.md) - Setting up Fory with compatible mode
diff --git a/docs/docs/guide/kotlin/fory-creation.md
b/docs/docs/guide/kotlin/fory-creation.md
new file mode 100644
index 000000000..1ccf6ff2c
--- /dev/null
+++ b/docs/docs/guide/kotlin/fory-creation.md
@@ -0,0 +1,116 @@
+---
+title: Fory Creation
+sidebar_position: 1
+id: kotlin_fory_creation
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page covers Kotlin-specific requirements for creating Fory instances.
+
+## Basic Setup
+
+When using Fory for Kotlin serialization, register Kotlin serializers via
`KotlinSerializers.registerSerializers(fory)`:
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+val fory = Fory.builder()
+ .requireClassRegistration(true)
+ .build()
+
+// Register Kotlin serializers
+KotlinSerializers.registerSerializers(fory)
+```
+
+## Thread Safety
+
+Fory instance creation is not cheap. Instances should be shared between
multiple serializations.
+
+### Single-Thread Usage
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+object ForyHolder {
+ val fory: Fory = Fory.builder()
+ .requireClassRegistration(true)
+ .build().also {
+ KotlinSerializers.registerSerializers(it)
+ }
+}
+```
+
+### Multi-Thread Usage
+
+For multi-threaded applications, use `ThreadSafeFory`:
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.ThreadSafeFory
+import org.apache.fory.ThreadLocalFory
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+object ForyHolder {
+ val fory: ThreadSafeFory = ThreadLocalFory { classLoader ->
+ Fory.builder()
+ .withClassLoader(classLoader)
+ .requireClassRegistration(true)
+ .build().also {
+ KotlinSerializers.registerSerializers(it)
+ }
+ }
+}
+```
+
+### Using Builder Methods
+
+```kotlin
+// Thread-safe Fory
+val fory: ThreadSafeFory = Fory.builder()
+ .requireClassRegistration(true)
+ .buildThreadSafeFory()
+
+KotlinSerializers.registerSerializers(fory)
+```
+
+## Configuration Options
+
+All configuration options from Fory Java are available. See [Java
Configuration Options](../java/configuration.md) for the complete list.
+
+Common options for Kotlin:
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.config.CompatibleMode
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+val fory = Fory.builder()
+ // Enable reference tracking for circular references
+ .withRefTracking(true)
+ // Enable schema evolution support
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ // Enable async compilation for better startup performance
+ .withAsyncCompilation(true)
+ // Compression options
+ .withIntCompressed(true)
+ .withLongCompressed(true)
+ .build()
+
+KotlinSerializers.registerSerializers(fory)
+```
diff --git a/docs/docs/guide/kotlin/index.md b/docs/docs/guide/kotlin/index.md
index ff445107d..6975c8958 100644
--- a/docs/docs/guide/kotlin/index.md
+++ b/docs/docs/guide/kotlin/index.md
@@ -1,7 +1,7 @@
---
-title: Kotlin Serialization
+title: Kotlin Serialization Guide
sidebar_position: 0
-id: scala_serialization_index
+id: kotlin_serialization_index
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -18,3 +18,91 @@ license: |
See the License for the specific language governing permissions and
limitations under the License.
---
+
+Apache Foryβ’ Kotlin provides optimized serializers for Kotlin types, built on
top of Fory Java. Most standard Kotlin types work out of the box with the
default Fory Java implementation, while Fory Kotlin adds additional support for
Kotlin-specific types.
+
+Supported types include:
+
+- `data class` serialization
+- Unsigned primitives: `UByte`, `UShort`, `UInt`, `ULong`
+- Unsigned arrays: `UByteArray`, `UShortArray`, `UIntArray`, `ULongArray`
+- Stdlib types: `Pair`, `Triple`, `Result`
+- Ranges: `IntRange`, `LongRange`, `CharRange`, and progressions
+- Collections: `ArrayDeque`, empty collections (`emptyList`, `emptyMap`,
`emptySet`)
+- `kotlin.time.Duration`, `kotlin.text.Regex`, `kotlin.uuid.Uuid`
+
+## Features
+
+Fory Kotlin inherits all features from Fory Java, plus Kotlin-specific
optimizations:
+
+- **High Performance**: JIT code generation, zero-copy, 20-170x faster than
traditional serialization
+- **Kotlin Type Support**: Optimized serializers for data classes, unsigned
types, ranges, and stdlib types
+- **Default Value Support**: Automatic handling of Kotlin data class default
parameters during schema evolution
+- **Schema Evolution**: Forward/backward compatibility for class schema changes
+
+See [Java Features](../java/index.md#features) for complete feature list.
+
+## Installation
+
+### Maven
+
+```xml
+<dependency>
+ <groupId>org.apache.fory</groupId>
+ <artifactId>fory-kotlin</artifactId>
+ <version>0.13.2</version>
+</dependency>
+```
+
+### Gradle
+
+```kotlin
+implementation("org.apache.fory:fory-kotlin:0.13.2")
+```
+
+## Quick Start
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.ThreadSafeFory
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+data class Person(val name: String, val id: Long, val github: String)
+data class Point(val x: Int, val y: Int, val z: Int)
+
+fun main() {
+ // Create Fory instance (should be reused)
+ val fory: ThreadSafeFory = Fory.builder()
+ .requireClassRegistration(true)
+ .buildThreadSafeFory()
+
+ // Register Kotlin serializers
+ KotlinSerializers.registerSerializers(fory)
+
+ // Register your classes
+ fory.register(Person::class.java)
+ fory.register(Point::class.java)
+
+ val p = Person("Shawn Yang", 1, "https://github.com/chaokunyang")
+ println(fory.deserialize(fory.serialize(p)))
+ println(fory.deserialize(fory.serialize(Point(1, 2, 3))))
+}
+```
+
+## Built on Fory Java
+
+Fory Kotlin is built on top of Fory Java. Most configuration options,
features, and concepts from Fory Java apply directly to Kotlin. Refer to the
Java documentation for:
+
+- [Configuration Options](../java/configuration.md) - All ForyBuilder options
+- [Basic Serialization](../java/basic-serialization.md) - Serialization
patterns and APIs
+- [Type Registration](../java/type-registration.md) - Class registration and
security
+- [Schema Evolution](../java/schema-evolution.md) - Forward/backward
compatibility
+- [Custom Serializers](../java/custom-serializers.md) - Implement custom
serializers
+- [Compression](../java/compression.md) - Int, long, and string compression
+- [Troubleshooting](../java/troubleshooting.md) - Common issues and solutions
+
+## Kotlin-Specific Documentation
+
+- [Fory Creation](fory-creation.md) - Kotlin-specific Fory setup requirements
+- [Type Serialization](type-serialization.md) - Serializing Kotlin types
+- [Default Values](default-values.md) - Kotlin data class default values
support
diff --git a/docs/docs/guide/kotlin/type-serialization.md
b/docs/docs/guide/kotlin/type-serialization.md
new file mode 100644
index 000000000..c555245e8
--- /dev/null
+++ b/docs/docs/guide/kotlin/type-serialization.md
@@ -0,0 +1,184 @@
+---
+title: Type Serialization
+sidebar_position: 2
+id: kotlin_type_serialization
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page covers serialization of Kotlin-specific types.
+
+## Setup
+
+All examples assume the following setup:
+
+```kotlin
+import org.apache.fory.Fory
+import org.apache.fory.serializer.kotlin.KotlinSerializers
+
+val fory = Fory.builder()
+ .requireClassRegistration(false)
+ .build()
+
+KotlinSerializers.registerSerializers(fory)
+```
+
+## Data Class
+
+```kotlin
+data class Person(val name: String, val age: Int, val id: Long)
+
+fory.register(Person::class.java)
+
+val p = Person("John", 30, 1L)
+println(fory.deserialize(fory.serialize(p)))
+```
+
+## Unsigned Primitives
+
+Kotlin unsigned types are fully supported:
+
+```kotlin
+val uByte: UByte = 255u
+val uShort: UShort = 65535u
+val uInt: UInt = 4294967295u
+val uLong: ULong = 18446744073709551615u
+
+println(fory.deserialize(fory.serialize(uByte)))
+println(fory.deserialize(fory.serialize(uShort)))
+println(fory.deserialize(fory.serialize(uInt)))
+println(fory.deserialize(fory.serialize(uLong)))
+```
+
+## Unsigned Arrays
+
+```kotlin
+val uByteArray = ubyteArrayOf(1u, 2u, 255u)
+val uShortArray = ushortArrayOf(1u, 2u, 65535u)
+val uIntArray = uintArrayOf(1u, 2u, 4294967295u)
+val uLongArray = ulongArrayOf(1u, 2u, 18446744073709551615u)
+
+println(fory.deserialize(fory.serialize(uByteArray)).contentToString())
+println(fory.deserialize(fory.serialize(uShortArray)).contentToString())
+println(fory.deserialize(fory.serialize(uIntArray)).contentToString())
+println(fory.deserialize(fory.serialize(uLongArray)).contentToString())
+```
+
+## Stdlib Types
+
+### Pair and Triple
+
+```kotlin
+val pair = Pair("key", 42)
+val triple = Triple("a", "b", "c")
+
+println(fory.deserialize(fory.serialize(pair)))
+println(fory.deserialize(fory.serialize(triple)))
+```
+
+### Result
+
+```kotlin
+val success: Result<Int> = Result.success(42)
+val failure: Result<Int> = Result.failure(Exception("error"))
+
+println(fory.deserialize(fory.serialize(success)))
+println(fory.deserialize(fory.serialize(failure)))
+```
+
+## Ranges and Progressions
+
+```kotlin
+val intRange = 1..10
+val longRange = 1L..100L
+val charRange = 'a'..'z'
+
+println(fory.deserialize(fory.serialize(intRange)))
+println(fory.deserialize(fory.serialize(longRange)))
+println(fory.deserialize(fory.serialize(charRange)))
+
+// Progressions
+val intProgression = 1..10 step 2
+val longProgression = 1L..100L step 10
+
+println(fory.deserialize(fory.serialize(intProgression)))
+println(fory.deserialize(fory.serialize(longProgression)))
+```
+
+## Collections
+
+### ArrayDeque
+
+```kotlin
+val deque = ArrayDeque<String>()
+deque.addFirst("first")
+deque.addLast("last")
+
+println(fory.deserialize(fory.serialize(deque)))
+```
+
+### Empty Collections
+
+```kotlin
+val emptyList = emptyList<String>()
+val emptySet = emptySet<Int>()
+val emptyMap = emptyMap<String, Int>()
+
+println(fory.deserialize(fory.serialize(emptyList)))
+println(fory.deserialize(fory.serialize(emptySet)))
+println(fory.deserialize(fory.serialize(emptyMap)))
+```
+
+## Duration
+
+```kotlin
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
+
+val duration: Duration = 2.hours + 30.minutes
+
+println(fory.deserialize(fory.serialize(duration)))
+```
+
+## Regex
+
+```kotlin
+val regex = Regex("[a-zA-Z]+")
+
+println(fory.deserialize(fory.serialize(regex)))
+```
+
+## UUID (Kotlin 2.0+)
+
+```kotlin
+import kotlin.uuid.Uuid
+
+val uuid = Uuid.random()
+
+println(fory.deserialize(fory.serialize(uuid)))
+```
+
+## Types Working Out of the Box
+
+The following types work with the default Fory Java implementation without
needing `KotlinSerializers`:
+
+- **Primitives**: `Byte`, `Boolean`, `Int`, `Short`, `Long`, `Char`, `Float`,
`Double`
+- **String**: `String`
+- **Collections**: `ArrayList`, `HashMap`, `HashSet`, `LinkedHashSet`,
`LinkedHashMap`
+- **Arrays**: `Array`, `BooleanArray`, `ByteArray`, `CharArray`,
`DoubleArray`, `FloatArray`, `IntArray`, `LongArray`, `ShortArray`
+
+However, it's recommended to always call
`KotlinSerializers.registerSerializers(fory)` to ensure all Kotlin types are
properly supported.
diff --git a/docs/docs/guide/rust/index.md b/docs/docs/guide/rust/index.md
index d4b7eebbf..522fbf3c0 100644
--- a/docs/docs/guide/rust/index.md
+++ b/docs/docs/guide/rust/index.md
@@ -31,7 +31,7 @@ The Rust implementation provides versatile and
high-performance serialization wi
- **π Circular References**: Automatic tracking of shared and circular
references with `Rc`/`Arc` and weak pointers
- **𧬠Polymorphic**: Serialize trait objects with `Box<dyn Trait>`, `Rc<dyn
Trait>`, and `Arc<dyn Trait>`
- **π¦ Schema Evolution**: Compatible mode for independent schema changes
-- **β‘ Two Modes**: Object graph serialization and zero-copy row-based format
+- **β‘ Two Formats**: Object graph serialization and zero-copy row-based format
## Crates
diff --git a/docs/docs/guide/rust_guide.md b/docs/docs/guide/rust_guide.md
index 5eed8c467..2b7f97dd8 100644
--- a/docs/docs/guide/rust_guide.md
+++ b/docs/docs/guide/rust_guide.md
@@ -36,7 +36,7 @@ The Rust implementation provides versatile and
high-performance serialization wi
- **π Circular References**: Automatic tracking of shared and circular
references with `Rc`/`Arc` and weak pointers
- **𧬠Polymorphic**: Serialize trait objects with `Box<dyn Trait>`, `Rc<dyn
Trait>`, and `Arc<dyn Trait>`
- **π¦ Schema Evolution**: Compatible mode for independent schema changes
-- **β‘ Two Modes**: Object graph serialization and zero-copy row-based format
+- **β‘ Two Formats**: Object graph serialization and zero-copy row-based format
## π¦ Crates
diff --git a/docs/docs/guide/scala/default-values.md
b/docs/docs/guide/scala/default-values.md
new file mode 100644
index 000000000..6c13178f0
--- /dev/null
+++ b/docs/docs/guide/scala/default-values.md
@@ -0,0 +1,186 @@
+---
+title: Default Values
+sidebar_position: 3
+id: scala_default_values
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory supports Scala class default values during deserialization when using
compatible mode. This feature enables forward/backward compatibility when case
classes or regular Scala classes have default parameters.
+
+## Overview
+
+When a Scala class has default parameters, the Scala compiler generates
methods in the companion object (for case classes) or in the class itself (for
regular Scala classes) like `apply$default$1`, `apply$default$2`, etc. that
return the default values. Fory can detect these methods and use them when
deserializing objects where certain fields are missing from the serialized data.
+
+## Supported Class Types
+
+Fory supports default values for:
+
+- **Case classes** with default parameters
+- **Regular Scala classes** with default parameters in their primary
constructor
+- **Nested case classes** with default parameters
+
+## How It Works
+
+1. **Detection**: Fory detects if a class is a Scala class by checking for the
presence of default value methods (`apply$default$N` or `$default$N`).
+
+2. **Default Value Discovery**:
+ - For case classes: Fory scans the companion object for methods named
`apply$default$1`, `apply$default$2`, etc.
+ - For regular Scala classes: Fory scans the class itself for methods named
`$default$1`, `$default$2`, etc.
+
+3. **Field Mapping**: During deserialization, Fory identifies fields that
exist in the target class but are missing from the serialized data.
+
+4. **Value Application**: After reading all available fields from the
serialized data, Fory applies default values to any missing fields.
+
+## Usage
+
+This feature is automatically enabled when:
+
+- Compatible mode is enabled (`withCompatibleMode(CompatibleMode.COMPATIBLE)`)
+- The target class is detected as a Scala class with default values
+- A field is missing from the serialized data but exists in the target class
+
+No additional configuration is required.
+
+## Examples
+
+### Case Class with Default Values
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.config.CompatibleMode
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+// Class WITHOUT default values (for serialization)
+case class PersonV1(name: String)
+
+// Class WITH default values (for deserialization)
+case class PersonV2(name: String, age: Int = 25, city: String = "Unknown")
+
+val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+
+// Serialize using class without default values
+val original = PersonV1("John")
+val serialized = fory.serialize(original)
+
+// Deserialize into class with default values
+// Missing fields will use defaults
+val deserialized = fory.deserialize(serialized).asInstanceOf[PersonV2]
+// deserialized.name == "John"
+// deserialized.age == 25 (default)
+// deserialized.city == "Unknown" (default)
+```
+
+### Regular Scala Class with Default Values
+
+```scala
+// Class WITHOUT default values (for serialization)
+class EmployeeV1(val name: String)
+
+// Class WITH default values (for deserialization)
+class EmployeeV2(
+ val name: String,
+ val age: Int = 30,
+ val department: String = "Engineering"
+)
+
+val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+
+// Serialize using class without default values
+val original = new EmployeeV1("Jane")
+val serialized = fory.serialize(original)
+
+// Deserialize into class with default values
+val deserialized = fory.deserialize(serialized).asInstanceOf[EmployeeV2]
+// deserialized.name == "Jane"
+// deserialized.age == 30 (default)
+// deserialized.department == "Engineering" (default)
+```
+
+### Complex Default Values
+
+Default values can be complex expressions:
+
+```scala
+// Class WITHOUT default values (for serialization)
+case class ConfigV1(name: String)
+
+// Class WITH default values (for deserialization)
+case class ConfigV2(
+ name: String,
+ settings: Map[String, String] = Map("default" -> "value"),
+ tags: List[String] = List("default"),
+ enabled: Boolean = true
+)
+
+val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+
+val original = ConfigV1("myConfig")
+val serialized = fory.serialize(original)
+
+val deserialized = fory.deserialize(serialized).asInstanceOf[ConfigV2]
+// deserialized.name == "myConfig"
+// deserialized.settings == Map("default" -> "value")
+// deserialized.tags == List("default")
+// deserialized.enabled == true
+```
+
+### Nested Case Classes
+
+```scala
+object Models {
+ // Class WITHOUT default values (for serialization)
+ case class PersonV1(name: String)
+
+ // Classes WITH default values (for deserialization)
+ case class Address(street: String, city: String = "DefaultCity")
+ case class PersonV2(name: String, address: Address =
Address("DefaultStreet"))
+}
+
+val fory = Fory.builder()
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+
+val original = Models.PersonV1("Alice")
+val serialized = fory.serialize(original)
+
+val deserialized = fory.deserialize(serialized).asInstanceOf[Models.PersonV2]
+// deserialized.name == "Alice"
+// deserialized.address == Address("DefaultStreet", "DefaultCity")
+```
+
+## Related Topics
+
+- [Schema Evolution](../java/schema-evolution.md) - Forward/backward
compatibility in Java
+- [Fory Creation](fory-creation.md) - Setting up Fory with compatible mode
diff --git a/docs/docs/guide/scala/fory-creation.md
b/docs/docs/guide/scala/fory-creation.md
new file mode 100644
index 000000000..278d72318
--- /dev/null
+++ b/docs/docs/guide/scala/fory-creation.md
@@ -0,0 +1,139 @@
+---
+title: Fory Creation
+sidebar_position: 1
+id: scala_fory_creation
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page covers Scala-specific requirements for creating Fory instances.
+
+## Basic Setup
+
+When using Fory for Scala serialization, you must:
+
+1. Enable Scala optimization via `withScalaOptimizationEnabled(true)`
+2. Register Scala serializers via `ScalaSerializers.registerSerializers(fory)`
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+val fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+// Register optimized Fory serializers for Scala
+ScalaSerializers.registerSerializers(fory)
+```
+
+## Registering Scala Internal Types
+
+Depending on the object types you serialize, you may need to register some
Scala internal types:
+
+```scala
+fory.register(Class.forName("scala.Enumeration.Val"))
+```
+
+To avoid such registration, you can disable class registration:
+
+```scala
+val fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .requireClassRegistration(false)
+ .build()
+```
+
+> **Note**: Disabling class registration allows deserialization of unknown
types. This is more flexible but may be insecure if the classes contain
malicious code.
+
+## Reference Tracking
+
+Circular references are common in Scala. Reference tracking should be enabled
with `withRefTracking(true)`:
+
+```scala
+val fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .withRefTracking(true)
+ .build()
+```
+
+> **Note**: If you don't enable reference tracking,
[StackOverflowError](https://github.com/apache/fory/issues/1032) may occur for
some Scala versions when serializing Scala Enumeration.
+
+## Thread Safety
+
+Fory instance creation is not cheap. Instances should be shared between
multiple serializations.
+
+### Single-Thread Usage
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+object ForyHolder {
+ val fory: Fory = {
+ val f = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .build()
+ ScalaSerializers.registerSerializers(f)
+ f
+ }
+}
+```
+
+### Multi-Thread Usage
+
+For multi-threaded applications, use `ThreadSafeFory`:
+
+```scala
+import org.apache.fory.ThreadSafeFory
+import org.apache.fory.ThreadLocalFory
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+object ForyHolder {
+ val fory: ThreadSafeFory = new ThreadLocalFory(classLoader => {
+ val f = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .withClassLoader(classLoader)
+ .build()
+ ScalaSerializers.registerSerializers(f)
+ f
+ })
+}
+```
+
+## Configuration Options
+
+All configuration options from Fory Java are available. See [Java
Configuration Options](../java/configuration.md) for the complete list.
+
+Common options for Scala:
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.config.CompatibleMode
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+val fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ // Enable reference tracking for circular references
+ .withRefTracking(true)
+ // Enable schema evolution support
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ // Enable async compilation for better startup performance
+ .withAsyncCompilation(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+```
diff --git a/docs/docs/guide/scala/index.md b/docs/docs/guide/scala/index.md
index 66c73f379..7d158bcf1 100644
--- a/docs/docs/guide/scala/index.md
+++ b/docs/docs/guide/scala/index.md
@@ -1,5 +1,5 @@
---
-title: Scala Serialization
+title: Scala Serialization Guide
sidebar_position: 0
id: scala_serialization_index
license: |
@@ -18,3 +18,83 @@ license: |
See the License for the specific language governing permissions and
limitations under the License.
---
+
+Apache Foryβ’ Scala provides optimized serializers for Scala types, built on
top of Fory Java. It supports all Scala object serialization:
+
+- `case` class serialization
+- `pojo/bean` class serialization
+- `object` singleton serialization
+- `collection` serialization (Seq, List, Map, etc.)
+- `tuple` and `either` types
+- `Option` types
+- Scala 2 and 3 enumerations
+
+Both Scala 2 and Scala 3 are supported.
+
+## Features
+
+Fory Scala inherits all features from Fory Java, plus Scala-specific
optimizations:
+
+- **High Performance**: JIT code generation, zero-copy, 20-170x faster than
traditional serialization
+- **Scala Type Support**: Optimized serializers for case classes, singletons,
collections, tuples, Option, Either
+- **Default Value Support**: Automatic handling of Scala class default
parameters during schema evolution
+- **Singleton Preservation**: `object` singletons maintain referential
equality after deserialization
+- **Schema Evolution**: Forward/backward compatibility for class schema changes
+
+See [Java Features](../java/index.md#features) for complete feature list.
+
+## Installation
+
+Add the dependency with sbt:
+
+```sbt
+libraryDependencies += "org.apache.fory" %% "fory-scala" % "0.13.2"
+```
+
+## Quick Start
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+case class Person(name: String, id: Long, github: String)
+case class Point(x: Int, y: Int, z: Int)
+
+object ScalaExample {
+ // Create Fory with Scala optimization enabled
+ val fory: Fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ // Register optimized Fory serializers for Scala
+ ScalaSerializers.registerSerializers(fory)
+
+ // Register your classes
+ fory.register(classOf[Person])
+ fory.register(classOf[Point])
+
+ def main(args: Array[String]): Unit = {
+ val p = Person("Shawn Yang", 1, "https://github.com/chaokunyang")
+ println(fory.deserialize(fory.serialize(p)))
+ println(fory.deserialize(fory.serialize(Point(1, 2, 3))))
+ }
+}
+```
+
+## Built on Fory Java
+
+Fory Scala is built on top of Fory Java. Most configuration options, features,
and concepts from Fory Java apply directly to Scala. Refer to the Java
documentation for:
+
+- [Configuration Options](../java/configuration.md) - All ForyBuilder options
+- [Basic Serialization](../java/basic-serialization.md) - Serialization
patterns and APIs
+- [Type Registration](../java/type-registration.md) - Class registration and
security
+- [Schema Evolution](../java/schema-evolution.md) - Forward/backward
compatibility
+- [Custom Serializers](../java/custom-serializers.md) - Implement custom
serializers
+- [Compression](../java/compression.md) - Int, long, and string compression
+- [Troubleshooting](../java/troubleshooting.md) - Common issues and solutions
+
+## Scala-Specific Documentation
+
+- [Fory Creation](fory-creation.md) - Scala-specific Fory setup requirements
+- [Type Serialization](type-serialization.md) - Serializing Scala types
+- [Default Values](default-values.md) - Scala class default values support
diff --git a/docs/docs/guide/scala/type-serialization.md
b/docs/docs/guide/scala/type-serialization.md
new file mode 100644
index 000000000..f8b8107e1
--- /dev/null
+++ b/docs/docs/guide/scala/type-serialization.md
@@ -0,0 +1,171 @@
+---
+title: Type Serialization
+sidebar_position: 2
+id: scala_type_serialization
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page covers serialization of Scala-specific types.
+
+## Setup
+
+All examples assume the following setup:
+
+```scala
+import org.apache.fory.Fory
+import org.apache.fory.serializer.scala.ScalaSerializers
+
+val fory = Fory.builder()
+ .withScalaOptimizationEnabled(true)
+ .build()
+
+ScalaSerializers.registerSerializers(fory)
+```
+
+## Case Class
+
+```scala
+case class Person(github: String, age: Int, id: Long)
+
+fory.register(classOf[Person])
+
+val p = Person("https://github.com/chaokunyang", 18, 1)
+println(fory.deserialize(fory.serialize(p)))
+```
+
+## POJO Class
+
+```scala
+class Foo(f1: Int, f2: String) {
+ override def toString: String = s"Foo($f1, $f2)"
+}
+
+fory.register(classOf[Foo])
+
+println(fory.deserialize(fory.serialize(new Foo(1, "chaokunyang"))))
+```
+
+## Object Singleton
+
+Scala `object` singletons are serialized and deserialized to the same instance:
+
+```scala
+object MySingleton {
+ val value = 42
+}
+
+fory.register(MySingleton.getClass)
+
+val o1 = fory.deserialize(fory.serialize(MySingleton))
+val o2 = fory.deserialize(fory.serialize(MySingleton))
+println(o1 == o2) // true
+```
+
+## Collection
+
+Scala collections are fully supported:
+
+```scala
+val seq = Seq(1, 2)
+val list = List("a", "b")
+val map = Map("a" -> 1, "b" -> 2)
+
+println(fory.deserialize(fory.serialize(seq)))
+println(fory.deserialize(fory.serialize(list)))
+println(fory.deserialize(fory.serialize(map)))
+```
+
+## Tuple
+
+All Scala tuple types (Tuple1 through Tuple22) are supported:
+
+```scala
+val tuple2 = (100, 10000L)
+println(fory.deserialize(fory.serialize(tuple2)))
+
+val tuple4 = (100, 10000L, 10000L, "str")
+println(fory.deserialize(fory.serialize(tuple4)))
+```
+
+## Enum
+
+### Scala 3 Enum
+
+```scala
+enum Color { case Red, Green, Blue }
+
+fory.register(classOf[Color])
+
+println(fory.deserialize(fory.serialize(Color.Green)))
+```
+
+### Scala 2 Enumeration
+
+```scala
+object ColorEnum extends Enumeration {
+ type ColorEnum = Value
+ val Red, Green, Blue = Value
+}
+
+fory.register(Class.forName("scala.Enumeration.Val"))
+
+println(fory.deserialize(fory.serialize(ColorEnum.Green)))
+```
+
+> **Note**: For Scala 2 Enumeration, you may need to register
`scala.Enumeration.Val` or enable reference tracking to avoid
`StackOverflowError`.
+
+## Option
+
+```scala
+val some: Option[Long] = Some(100)
+println(fory.deserialize(fory.serialize(some)))
+
+val none: Option[Long] = None
+println(fory.deserialize(fory.serialize(none)))
+```
+
+## Either
+
+```scala
+val right: Either[String, Int] = Right(42)
+println(fory.deserialize(fory.serialize(right)))
+
+val left: Either[String, Int] = Left("error")
+println(fory.deserialize(fory.serialize(left)))
+```
+
+## Nested Types
+
+Complex nested structures are fully supported:
+
+```scala
+case class Address(street: String, city: String)
+case class Company(name: String, address: Address)
+case class Employee(name: String, company: Company, tags: List[String])
+
+fory.register(classOf[Address])
+fory.register(classOf[Company])
+fory.register(classOf[Employee])
+
+val employee = Employee(
+ "John",
+ Company("Acme", Address("123 Main St", "Springfield")),
+ List("developer", "scala")
+)
+
+println(fory.deserialize(fory.serialize(employee)))
+```
diff --git a/docs/docs/guide/xlang/row_format.md
b/docs/docs/guide/xlang/row_format.md
new file mode 100644
index 000000000..ec6df6d63
--- /dev/null
+++ b/docs/docs/guide/xlang/row_format.md
@@ -0,0 +1,205 @@
+---
+title: Row Format Guide
+sidebar_position: 5
+id: row_format
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+## Java
+
+```java
+public class Bar {
+ String f1;
+ List<Long> f2;
+}
+
+public class Foo {
+ int f1;
+ List<Integer> f2;
+ Map<String, Integer> f3;
+ List<Bar> f4;
+}
+
+RowEncoder<Foo> encoder = Encoders.bean(Foo.class);
+Foo foo = new Foo();
+foo.f1 = 10;
+foo.f2 = IntStream.range(0, 1000000).boxed().collect(Collectors.toList());
+foo.f3 = IntStream.range(0, 1000000).boxed().collect(Collectors.toMap(i ->
"k"+i, i->i));
+List<Bar> bars = new ArrayList<>(1000000);
+for (int i = 0; i < 1000000; i++) {
+ Bar bar = new Bar();
+ bar.f1 = "s"+i;
+ bar.f2 = LongStream.range(0, 10).boxed().collect(Collectors.toList());
+ bars.add(bar);
+}
+foo.f4 = bars;
+// Can be zero-copy read by python
+BinaryRow binaryRow = encoder.toRow(foo);
+// can be data from python
+Foo newFoo = encoder.fromRow(binaryRow);
+// zero-copy read List<Integer> f2
+BinaryArray binaryArray2 = binaryRow.getArray(1);
+// zero-copy read List<Bar> f4
+BinaryArray binaryArray4 = binaryRow.getArray(3);
+// zero-copy read 11th element of `readList<Bar> f4`
+BinaryRow barStruct = binaryArray4.getStruct(10);
+
+// zero-copy read 6th of f2 of 11th element of `readList<Bar> f4`
+barStruct.getArray(1).getInt64(5);
+RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class);
+// deserialize part of data.
+Bar newBar = barEncoder.fromRow(barStruct);
+Bar newBar2 = barEncoder.fromRow(binaryArray4.getStruct(20));
+```
+
+## Python
+
+```python
+@dataclass
+class Bar:
+ f1: str
+ f2: List[pa.int64]
+@dataclass
+class Foo:
+ f1: pa.int32
+ f2: List[pa.int32]
+ f3: Dict[str, pa.int32]
+ f4: List[Bar]
+
+encoder = pyfory.encoder(Foo)
+foo = Foo(f1=10, f2=list(range(1000_000)),
+ f3={f"k{i}": i for i in range(1000_000)},
+ f4=[Bar(f1=f"s{i}", f2=list(range(10))) for i in range(1000_000)])
+binary: bytes = encoder.to_row(foo).to_bytes()
+print(f"start: {datetime.datetime.now()}")
+foo_row = pyfory.RowData(encoder.schema, binary)
+print(foo_row.f2[100000], foo_row.f4[100000].f1, foo_row.f4[200000].f2[5])
+print(f"end: {datetime.datetime.now()}")
+
+binary = pickle.dumps(foo)
+print(f"pickle start: {datetime.datetime.now()}")
+new_foo = pickle.loads(binary)
+print(new_foo.f2[100000], new_foo.f4[100000].f1, new_foo.f4[200000].f2[5])
+print(f"pickle end: {datetime.datetime.now()}")
+```
+
+### Apache Arrow Support
+
+Apache Foryβ’ Row Format also supports automatic conversion from/to Arrow
Table/RecordBatch.
+
+Java:
+
+```java
+Schema schema = TypeInference.inferSchema(BeanA.class);
+ArrowWriter arrowWriter = ArrowUtils.createArrowWriter(schema);
+Encoder<BeanA> encoder = Encoders.rowEncoder(BeanA.class);
+for (int i = 0; i < 10; i++) {
+ BeanA beanA = BeanA.createBeanA(2);
+ arrowWriter.write(encoder.toRow(beanA));
+}
+return arrowWriter.finishAsRecordBatch();
+```
+
+## Support for Interface and Extension Types
+
+Fory now supports row format mapping for Java `interface` types and subclassed
(`extends`) types, enabling more dynamic and flexible data schemas.
+
+These enhancements were introduced in
[#2243](https://github.com/apache/fory/pull/2243),
[#2250](https://github.com/apache/fory/pull/2250), and
[#2256](https://github.com/apache/fory/pull/2256).
+
+### Example: Interface Mapping with RowEncoder
+
+```java
+public interface Animal {
+ String speak();
+}
+
+public class Dog implements Animal {
+ public String name;
+
+ @Override
+ public String speak() {
+ return "Woof";
+ }
+}
+
+// Encode and decode using RowEncoder with interface type
+RowEncoder<Animal> encoder = Encoders.bean(Animal.class);
+Dog dog = new Dog();
+dog.name = "Bingo";
+BinaryRow row = encoder.toRow(dog);
+Animal decoded = encoder.fromRow(row);
+System.out.println(decoded.speak()); // Woof
+
+```
+
+### Example: Extension Type with RowEncoder
+
+```java
+public class Parent {
+ public String parentField;
+}
+
+public class Child extends Parent {
+ public String childField;
+}
+
+// Encode and decode using RowEncoder with parent class type
+RowEncoder<Parent> encoder = Encoders.bean(Parent.class);
+Child child = new Child();
+child.parentField = "Hello";
+child.childField = "World";
+BinaryRow row = encoder.toRow(child);
+Parent decoded = encoder.fromRow(row);
+
+```
+
+Python:
+
+```python
+import pyfory
+encoder = pyfory.encoder(Foo)
+encoder.to_arrow_record_batch([foo] * 10000)
+encoder.to_arrow_table([foo] * 10000)
+```
+
+C++
+
+```c++
+std::shared_ptr<ArrowWriter> arrow_writer;
+EXPECT_TRUE(
+ ArrowWriter::Make(schema, ::arrow::default_memory_pool(), &arrow_writer)
+ .ok());
+for (auto &row : rows) {
+ EXPECT_TRUE(arrow_writer->Write(row).ok());
+}
+std::shared_ptr<::arrow::RecordBatch> record_batch;
+EXPECT_TRUE(arrow_writer->Finish(&record_batch).ok());
+EXPECT_TRUE(record_batch->Validate().ok());
+EXPECT_EQ(record_batch->num_columns(), schema->num_fields());
+EXPECT_EQ(record_batch->num_rows(), row_nums);
+```
+
+```java
+Schema schema = TypeInference.inferSchema(BeanA.class);
+ArrowWriter arrowWriter = ArrowUtils.createArrowWriter(schema);
+Encoder<BeanA> encoder = Encoders.rowEncoder(BeanA.class);
+for (int i = 0; i < 10; i++) {
+ BeanA beanA = BeanA.createBeanA(2);
+ arrowWriter.write(encoder.toRow(beanA));
+}
+return arrowWriter.finishAsRecordBatch();
+```
diff --git a/docs/docs/guide/xlang/serialization.md
b/docs/docs/guide/xlang/serialization.md
new file mode 100644
index 000000000..a5715a60a
--- /dev/null
+++ b/docs/docs/guide/xlang/serialization.md
@@ -0,0 +1,610 @@
+---
+title: Xlang Serialization Guide
+sidebar_position: 4
+id: xlang_serialization
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+## Serialize built-in types
+
+Common types can be serialized automatically: primitive numeric types, string,
binary, array, list, map and so on.
+
+**Java**
+
+```java
+import org.apache.fory.*;
+import org.apache.fory.config.*;
+
+import java.util.*;
+
+public class Example1 {
+ public static void main(String[] args) {
+ Fory fory = Fory.builder().withLanguage(Language.XLANG).build();
+ List<Object> list = ofArrayList(true, false, "str", -1.1, 1, new int[100],
new double[20]);
+ byte[] bytes = fory.serialize(list);
+ // bytes can be data serialized by other languages.
+ fory.deserialize(bytes);
+ Map<Object, Object> map = new HashMap<>();
+ map.put("k1", "v1");
+ map.put("k2", list);
+ map.put("k3", -1);
+ bytes = fory.serialize(map);
+ // bytes can be data serialized by other languages.
+ fory.deserialize(bytes);
+ }
+}
+```
+
+**Python**
+
+```python
+import pyfory
+import numpy as np
+
+fory = pyfory.Fory()
+object_list = [True, False, "str", -1.1, 1,
+ np.full(100, 0, dtype=np.int32), np.full(20, 0.0,
dtype=np.double)]
+data = fory.serialize(object_list)
+# bytes can be data serialized by other languages.
+new_list = fory.deserialize(data)
+object_map = {"k1": "v1", "k2": object_list, "k3": -1}
+data = fory.serialize(object_map)
+# bytes can be data serialized by other languages.
+new_map = fory.deserialize(data)
+print(new_map)
+```
+
+**Golang**
+
+```go
+package main
+
+import forygo "github.com/apache/fory/fory/go/fory"
+import "fmt"
+
+func main() {
+ list := []interface{}{true, false, "str", -1.1, 1, make([]int32, 10),
make([]float64, 20)}
+ fory := forygo.NewFory()
+ bytes, err := fory.Marshal(list)
+ if err != nil {
+ panic(err)
+ }
+ var newValue interface{}
+ // bytes can be data serialized by other languages.
+ if err := fory.Unmarshal(bytes, &newValue); err != nil {
+ panic(err)
+ }
+ fmt.Println(newValue)
+ dict := map[string]interface{}{
+ "k1": "v1",
+ "k2": list,
+ "k3": -1,
+ }
+ bytes, err = fory.Marshal(dict)
+ if err != nil {
+ panic(err)
+ }
+ // bytes can be data serialized by other languages.
+ if err := fory.Unmarshal(bytes, &newValue); err != nil {
+ panic(err)
+ }
+ fmt.Println(newValue)
+}
+```
+
+**JavaScript**
+
+```javascript
+import Fory from "@apache-fory/fory";
+
+/**
+ * @apache-fory/hps use v8's fast-calls-api that can be called directly by
jit, ensure that the version of Node is 20 or above.
+ * Experimental feature, installation success cannot be guaranteed at this
moment
+ * If you are unable to install the module, replace it with `const hps = null;`
+ **/
+import hps from "@apache-fory/hps";
+
+const fory = new Fory({ hps });
+const input = fory.serialize("hello fory");
+const result = fory.deserialize(input);
+console.log(result);
+```
+
+**Rust**
+
+```rust
+use chrono::{NaiveDate, NaiveDateTime};
+use fory::{from_buffer, to_buffer, Fory};
+use std::collections::HashMap;
+
+fn run() {
+ let bin: Vec<u8> = to_buffer(&"hello".to_string());
+ let obj: String = from_buffer(&bin).expect("should success");
+ assert_eq!("hello".to_string(), obj);
+}
+```
+
+## Serialize custom types
+
+Serializing user-defined types needs registering the custom type using the
register API to establish the mapping relationship between the type in
different languages.
+
+**Java**
+
+```java
+import org.apache.fory.*;
+import org.apache.fory.config.*;
+import java.util.*;
+
+public class Example2 {
+ public static class SomeClass1 {
+ Object f1;
+ Map<Byte, Integer> f2;
+ }
+
+ public static class SomeClass2 {
+ Object f1;
+ String f2;
+ List<Object> f3;
+ Map<Byte, Integer> f4;
+ Byte f5;
+ Short f6;
+ Integer f7;
+ Long f8;
+ Float f9;
+ Double f10;
+ short[] f11;
+ List<Short> f12;
+ }
+
+ public static Object createObject() {
+ SomeClass1 obj1 = new SomeClass1();
+ obj1.f1 = true;
+ obj1.f2 = ofHashMap((byte) -1, 2);
+ SomeClass2 obj = new SomeClass2();
+ obj.f1 = obj1;
+ obj.f2 = "abc";
+ obj.f3 = ofArrayList("abc", "abc");
+ obj.f4 = ofHashMap((byte) 1, 2);
+ obj.f5 = Byte.MAX_VALUE;
+ obj.f6 = Short.MAX_VALUE;
+ obj.f7 = Integer.MAX_VALUE;
+ obj.f8 = Long.MAX_VALUE;
+ obj.f9 = 1.0f / 2;
+ obj.f10 = 1 / 3.0;
+ obj.f11 = new short[]{(short) 1, (short) 2};
+ obj.f12 = ofArrayList((short) -1, (short) 4);
+ return obj;
+ }
+
+ // mvn exec:java -Dexec.mainClass="org.apache.fory.examples.Example2"
+ public static void main(String[] args) {
+ Fory fory = Fory.builder().withLanguage(Language.XLANG).build();
+ fory.register(SomeClass1.class, "example.SomeClass1");
+ fory.register(SomeClass2.class, "example.SomeClass2");
+ byte[] bytes = fory.serialize(createObject());
+ // bytes can be data serialized by other languages.
+ System.out.println(fory.deserialize(bytes));
+ }
+}
+```
+
+**Python**
+
+```python
+from dataclasses import dataclass
+from typing import List, Dict, Any
+import pyfory, array
+
+
+@dataclass
+class SomeClass1:
+ f1: Any
+ f2: Dict[pyfory.Int8Type, pyfory.Int32Type]
+
+
+@dataclass
+class SomeClass2:
+ f1: Any = None
+ f2: str = None
+ f3: List[str] = None
+ f4: Dict[pyfory.Int8Type, pyfory.Int32Type] = None
+ f5: pyfory.Int8Type = None
+ f6: pyfory.Int16Type = None
+ f7: pyfory.Int32Type = None
+ # int type will be taken as `pyfory.Int64Type`.
+ # use `pyfory.Int32Type` for type hint if peer
+ # are more narrow type.
+ f8: int = None
+ f9: pyfory.Float32Type = None
+ # float type will be taken as `pyfory.Float64Type`
+ f10: float = None
+ f11: pyfory.Int16ArrayType = None
+ f12: List[pyfory.Int16Type] = None
+
+
+if __name__ == "__main__":
+ f = pyfory.Fory()
+ f.register_type(SomeClass1, typename="example.SomeClass1")
+ f.register_type(SomeClass2, typename="example.SomeClass2")
+ obj1 = SomeClass1(f1=True, f2={-1: 2})
+ obj = SomeClass2(
+ f1=obj1,
+ f2="abc",
+ f3=["abc", "abc"],
+ f4={1: 2},
+ f5=2 ** 7 - 1,
+ f6=2 ** 15 - 1,
+ f7=2 ** 31 - 1,
+ f8=2 ** 63 - 1,
+ f9=1.0 / 2,
+ f10=1 / 3.0,
+ f11=array.array("h", [1, 2]),
+ f12=[-1, 4],
+ )
+ data = f.serialize(obj)
+ # bytes can be data serialized by other languages.
+ print(f.deserialize(data))
+```
+
+**Golang**
+
+```go
+package main
+
+import forygo "github.com/apache/fory/fory/go/fory"
+import "fmt"
+
+func main() {
+ type SomeClass1 struct {
+ F1 interface{}
+ F2 string
+ F3 []interface{}
+ F4 map[int8]int32
+ F5 int8
+ F6 int16
+ F7 int32
+ F8 int64
+ F9 float32
+ F10 float64
+ F11 []int16
+ F12 fory.Int16Slice
+ }
+
+ type SomeClas2 struct {
+ F1 interface{}
+ F2 map[int8]int32
+ }
+ fory := forygo.NewFory()
+ if err := fory.RegisterNamedType(SomeClass1{}, "example.SomeClass1"); err !=
nil {
+ panic(err)
+ }
+ if err := fory.RegisterNamedType(SomeClass2{}, "example.SomeClass2"); err !=
nil {
+ panic(err)
+ }
+ obj1 := &SomeClass1{}
+ obj1.F1 = true
+ obj1.F2 = map[int8]int32{-1: 2}
+ obj := &SomeClass1{}
+ obj.F1 = obj1
+ obj.F2 = "abc"
+ obj.F3 = []interface{}{"abc", "abc"}
+ f4 := map[int8]int32{1: 2}
+ obj.F4 = f4
+ obj.F5 = fory.MaxInt8
+ obj.F6 = fory.MaxInt16
+ obj.F7 = fory.MaxInt32
+ obj.F8 = fory.MaxInt64
+ obj.F9 = 1.0 / 2
+ obj.F10 = 1 / 3.0
+ obj.F11 = []int16{1, 2}
+ obj.F12 = []int16{-1, 4}
+ bytes, err := fory.Marshal(obj);
+ if err != nil {
+ panic(err)
+ }
+ var newValue interface{}
+ // bytes can be data serialized by other languages.
+ if err := fory.Unmarshal(bytes, &newValue); err != nil {
+ panic(err)
+ }
+ fmt.Println(newValue)
+}
+```
+
+**JavaScript**
+
+```javascript
+import Fory, { Type, InternalSerializerType } from "@apache-fory/fory";
+
+/**
+ * @apache-fory/hps use v8's fast-calls-api that can be called directly by
jit, ensure that the version of Node is 20 or above.
+ * Experimental feature, installation success cannot be guaranteed at this
moment
+ * If you are unable to install the module, replace it with `const hps = null;`
+ **/
+import hps from "@apache-fory/hps";
+
+// Now we describe data structures using JSON, but in the future, we will use
more ways.
+const description = Type.object("example.foo", {
+ foo: Type.string(),
+});
+const fory = new Fory({ hps });
+const { serialize, deserialize } = fory.registerSerializer(description);
+const input = serialize({ foo: "hello fory" });
+const result = deserialize(input);
+console.log(result);
+```
+
+**Rust**
+
+```rust
+use chrono::{NaiveDate, NaiveDateTime};
+use fory::{from_buffer, to_buffer, Fory};
+use std::collections::HashMap;
+
+#[test]
+fn complex_struct() {
+ #[derive(Fory, Debug, PartialEq)]
+ #[tag("example.foo2")]
+ struct Animal {
+ category: String,
+ }
+
+ #[derive(Fory, Debug, PartialEq)]
+ #[tag("example.foo")]
+ struct Person {
+ c1: Vec<u8>, // binary
+ c2: Vec<i16>, // primitive array
+ animal: Vec<Animal>,
+ c3: Vec<Vec<u8>>,
+ name: String,
+ c4: HashMap<String, String>,
+ age: u16,
+ op: Option<String>,
+ op2: Option<String>,
+ date: NaiveDate,
+ time: NaiveDateTime,
+ c5: f32,
+ c6: f64,
+ }
+ let person: Person = Person {
+ c1: vec![1, 2, 3],
+ c2: vec![5, 6, 7],
+ c3: vec![vec![1, 2], vec![1, 3]],
+ animal: vec![Animal {
+ category: "Dog".to_string(),
+ }],
+ c4: HashMap::from([
+ ("hello1".to_string(), "hello2".to_string()),
+ ("hello2".to_string(), "hello3".to_string()),
+ ]),
+ age: 12,
+ name: "helo".to_string(),
+ op: Some("option".to_string()),
+ op2: None,
+ date: NaiveDate::from_ymd_opt(2025, 12, 12).unwrap(),
+ time: NaiveDateTime::from_timestamp_opt(1689912359, 0).unwrap(),
+ c5: 2.0,
+ c6: 4.0,
+ };
+
+ let bin: Vec<u8> = to_buffer(&person);
+ let obj: Person = from_buffer(&bin).expect("should success");
+ assert_eq!(person, obj);
+}
+```
+
+## Serialize Shared Reference and Circular Reference
+
+Shared reference and circular reference can be serialized automatically, no
duplicate data or recursion error.
+
+**Java**
+
+```java
+import org.apache.fory.*;
+import org.apache.fory.config.*;
+import java.util.*;
+
+public class ReferenceExample {
+ public static class SomeClass {
+ SomeClass f1;
+ Map<String, String> f2;
+ Map<String, String> f3;
+ }
+
+ public static Object createObject() {
+ SomeClass obj = new SomeClass();
+ obj.f1 = obj;
+ obj.f2 = ofHashMap("k1", "v1", "k2", "v2");
+ obj.f3 = obj.f2;
+ return obj;
+ }
+
+ // mvn exec:java -Dexec.mainClass="org.apache.fory.examples.ReferenceExample"
+ public static void main(String[] args) {
+ Fory fory = Fory.builder().withLanguage(Language.XLANG)
+ .withRefTracking(true).build();
+ fory.register(SomeClass.class, "example.SomeClass");
+ byte[] bytes = fory.serialize(createObject());
+ // bytes can be data serialized by other languages.
+ System.out.println(fory.deserialize(bytes));
+ }
+}
+```
+
+**Python**
+
+```python
+from typing import Dict
+import pyfory
+
+class SomeClass:
+ f1: "SomeClass"
+ f2: Dict[str, str]
+ f3: Dict[str, str]
+
+fory = pyfory.Fory(ref_tracking=True)
+fory.register_type(SomeClass, typename="example.SomeClass")
+obj = SomeClass()
+obj.f2 = {"k1": "v1", "k2": "v2"}
+obj.f1, obj.f3 = obj, obj.f2
+data = fory.serialize(obj)
+# bytes can be data serialized by other languages.
+print(fory.deserialize(data))
+```
+
+**Golang**
+
+```go
+package main
+
+import forygo "github.com/apache/fory/fory/go/fory"
+import "fmt"
+
+func main() {
+ type SomeClass struct {
+ F1 *SomeClass
+ F2 map[string]string
+ F3 map[string]string
+ }
+ fory := forygo.NewFory(true)
+ if err := fory.Register(SomeClass{}, 65); err != nil {
+ panic(err)
+ }
+ value := &SomeClass{F2: map[string]string{"k1": "v1", "k2": "v2"}}
+ value.F3 = value.F2
+ value.F1 = value
+ bytes, err := fory.Marshal(value)
+ if err != nil {
+ }
+ var newValue interface{}
+ // bytes can be data serialized by other languages.
+ if err := fory.Unmarshal(bytes, &newValue); err != nil {
+ panic(err)
+ }
+ fmt.Println(newValue)
+}
+```
+
+**JavaScript**
+
+```javascript
+import Fory, { Type } from '@apache-fory/fory';
+/**
+ * @apache-fory/hps use v8's fast-calls-api that can be called directly by
jit, ensure that the version of Node is 20 or above.
+ * Experimental feature, installation success cannot be guaranteed at this
moment
+ * If you are unable to install the module, replace it with `const hps = null;`
+ **/
+import hps from '@apache-fory/hps';
+
+const description = Type.object('example.foo', {
+ foo: Type.string(),
+ bar: Type.object('example.foo'),
+});
+
+const fory = new Fory({ hps });
+const { serialize, deserialize } = fory.registerSerializer(description);
+const data: any = {
+ foo: 'hello fory',
+};
+data.bar = data;
+const input = serialize(data);
+const result = deserialize(input);
+console.log(result.bar.foo === result.foo);
+```
+
+**JavaScript**
+Reference cannot be implemented because of rust ownership restrictions
+
+## Zero-Copy Serialization
+
+**Java**
+
+```java
+import org.apache.fory.*;
+import org.apache.fory.config.*;
+import org.apache.fory.serializer.BufferObject;
+import org.apache.fory.memory.MemoryBuffer;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class ZeroCopyExample {
+ // mvn exec:java -Dexec.mainClass="io.ray.fory.examples.ZeroCopyExample"
+ public static void main(String[] args) {
+ Fory fory = Fory.builder().withLanguage(Language.XLANG).build();
+ List<Object> list = ofArrayList("str", new byte[1000], new int[100], new
double[100]);
+ Collection<BufferObject> bufferObjects = new ArrayList<>();
+ byte[] bytes = fory.serialize(list, e -> !bufferObjects.add(e));
+ // bytes can be data serialized by other languages.
+ List<MemoryBuffer> buffers = bufferObjects.stream()
+ .map(BufferObject::toBuffer).collect(Collectors.toList());
+ System.out.println(fory.deserialize(bytes, buffers));
+ }
+}
+```
+
+**Python**
+
+```python
+import array
+import pyfory
+import numpy as np
+
+fory = pyfory.Fory()
+list_ = ["str", bytes(bytearray(1000)),
+ array.array("i", range(100)), np.full(100, 0.0, dtype=np.double)]
+serialized_objects = []
+data = fory.serialize(list_, buffer_callback=serialized_objects.append)
+buffers = [o.to_buffer() for o in serialized_objects]
+# bytes can be data serialized by other languages.
+print(fory.deserialize(data, buffers=buffers))
+```
+
+**Golang**
+
+```go
+package main
+
+import forygo "github.com/apache/fory/fory/go/fory"
+import "fmt"
+
+func main() {
+ fory := forygo.NewFory()
+ list := []interface{}{"str", make([]byte, 1000)}
+ buf := fory.NewByteBuffer(nil)
+ var bufferObjects []fory.BufferObject
+ fory.Serialize(buf, list, func(o fory.BufferObject) bool {
+ bufferObjects = append(bufferObjects, o)
+ return false
+ })
+ var newList []interface{}
+ var buffers []*fory.ByteBuffer
+ for _, o := range bufferObjects {
+ buffers = append(buffers, o.ToBuffer())
+ }
+ if err := fory.Deserialize(buf, &newList, buffers); err != nil {
+ panic(err)
+ }
+ fmt.Println(newList)
+}
+```
+
+**JavaScript**
+
+```javascript
+// Coming soon
+```
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]