blob: 58481ca792ee0d412a11c65f142c4d9a371c2ce1 [file] [view]
---
id: usage
title: Usage
sidebar_position: 1
---
This section provides quick examples for getting started with Apache Fory™.
## Choose A Mode
Apache Fory™ has two wire modes:
- **Xlang mode** is the default and the portable format for payloads shared across languages. Use it for cross-language services and for runtimes that expose only xlang mode: Dart, JavaScript/TypeScript, C#, and Swift.
- **Native mode** is selected with `xlang=false` or the equivalent builder option in Java, Scala, Kotlin, Python, C++, Go, and Rust. Use it for same-language traffic because it follows the runtime's native type system, supports a broader language-specific object surface, and is optimized for that runtime.
Xlang/default usage uses schema-compatible mode by default. Native mode uses schema-consistent payloads by default unless compatible mode is enabled explicitly.
## Xlang Mode
Use xlang mode when bytes need to cross runtime boundaries. Register custom types with the same numeric ID or namespace/type name on every peer.
Dual-mode runtimes set the xlang option explicitly in the examples below. Dart, JavaScript/TypeScript, C#, and Swift are xlang-only, so their examples do not show an xlang switch.
### Java
```java
import org.apache.fory.Fory;
public class XlangExample {
public record Person(String name, int age) {}
public static void main(String[] args) {
Fory fory = Fory.builder()
.withXlang(true)
.build();
fory.register(Person.class, "example", "Person");
Person person = new Person("chaokunyang", 28);
byte[] bytes = fory.serialize(person);
Person result = (Person) fory.deserialize(bytes);
System.out.println(result.name() + " " + result.age());
}
}
```
### Python
```python
from dataclasses import dataclass
import pyfory
@dataclass
class Person:
name: str
age: pyfory.Int32
fory = pyfory.Fory(xlang=True)
fory.register(Person, typename="example.Person")
person = Person(name="chaokunyang", age=28)
data = fory.serialize(person)
result = fory.deserialize(data)
print(result.name, result.age)
```
### Dart
```dart
import 'package:fory/fory.dart';
part 'person.fory.dart';
@ForyStruct()
class Person {
Person();
String name = '';
@ForyField(type: Int32Type())
int age = 0;
}
void main() {
final fory = Fory();
PersonFory.register(
fory,
Person,
namespace: 'example',
typeName: 'Person',
);
final person = Person()
..name = 'chaokunyang'
..age = 28;
final bytes = fory.serialize(person);
final result = fory.deserialize<Person>(bytes);
print('${result.name} ${result.age}');
}
```
### Go
```go
package main
import (
"fmt"
"github.com/apache/fory/go/fory"
)
type Person struct {
Name string
Age int32
}
func main() {
f := fory.New(fory.WithXlang(true))
if err := f.RegisterStruct(Person{}, 1); err != nil {
panic(err)
}
person := &Person{Name: "chaokunyang", Age: 28}
data, err := f.Serialize(person)
if err != nil {
panic(err)
}
var result Person
if err := f.Deserialize(data, &result); err != nil {
panic(err)
}
fmt.Printf("%s %d\n", result.Name, result.Age)
}
```
### Rust
```rust
use fory::{Error, Fory, ForyObject};
#[derive(ForyObject, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
}
fn main() -> Result<(), Error> {
let mut fory = Fory::builder().xlang(true).build();
fory.register_by_name::<Person>("example", "Person")?;
let person = Person {
name: "chaokunyang".to_string(),
age: 28,
};
let bytes = fory.serialize(&person)?;
let result: Person = fory.deserialize(&bytes)?;
assert_eq!(person, result);
Ok(())
}
```
### C++
```cpp
#include <cassert>
#include <string>
#include "fory/serialization/fory.h"
using namespace fory::serialization;
struct Person {
std::string name;
int32_t age;
bool operator==(const Person &other) const {
return name == other.name && age == other.age;
}
FORY_STRUCT(Person, name, age);
};
int main() {
auto fory = Fory::builder().xlang(true).build();
fory.register_struct<Person>(1);
Person person{"chaokunyang", 28};
auto bytes = fory.serialize(person).value();
auto result = fory.deserialize<Person>(bytes).value();
assert(person == result);
return 0;
}
```
### Scala
```scala
import org.apache.fory.Fory
import org.apache.fory.scala.ForyScala
case class Person(name: String, age: Int)
object Example {
def main(args: Array[String]): Unit = {
val fory: Fory = ForyScala.builder()
.withXlang(true)
.build()
fory.register(classOf[Person])
val bytes = fory.serialize(Person("chaokunyang", 28))
val result = fory.deserialize(bytes).asInstanceOf[Person]
println(s"${result.name} ${result.age}")
}
}
```
### Kotlin
```kotlin
import org.apache.fory.ThreadSafeFory
import org.apache.fory.kotlin.ForyKotlin
data class Person(val name: String, val age: Int)
fun main() {
val fory: ThreadSafeFory = ForyKotlin.builder()
.withXlang(true)
.requireClassRegistration(true)
.buildThreadSafeFory()
fory.register(Person::class.java)
val bytes = fory.serialize(Person("chaokunyang", 28))
val result = fory.deserialize(bytes) as Person
println("${result.name} ${result.age}")
}
```
### JavaScript / TypeScript
```typescript
import Fory, { Type } from "@apache-fory/core";
const personType = Type.struct(
{ typeName: "example.Person" },
{
name: Type.string(),
age: Type.int32(),
},
);
const fory = new Fory();
const { serialize, deserialize } = fory.register(personType);
const payload = serialize({ name: "chaokunyang", age: 28 });
const result = deserialize(payload);
console.log(result);
```
### C\#
```csharp
using Apache.Fory;
[ForyObject]
public sealed class Person
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
Fory fory = Fory.Builder().Build();
fory.Register<Person>(1);
Person person = new() { Name = "chaokunyang", Age = 28 };
byte[] data = fory.Serialize(person);
Person result = fory.Deserialize<Person>(data);
Console.WriteLine($"{result.Name} {result.Age}");
```
### Swift
```swift
import Fory
@ForyStruct
struct Person: Equatable {
var name: String = ""
var age: Int32 = 0
}
let fory = Fory()
fory.register(Person.self, id: 1)
let person = Person(name: "chaokunyang", age: 28)
let data = try fory.serialize(person)
let result: Person = try fory.deserialize(data)
print("\(result.name) \(result.age)")
```
For more cross-language rules and examples, see:
- [Cross-Language Serialization Guide](../guide/xlang/index.md)
- [Java Guide](../guide/java/index.md)
- [Python Guide](../guide/python/index.md)
- [Dart Guide](../guide/dart/index.md)
- [Go Guide](../guide/go/index.md)
- [Rust Guide](../guide/rust/index.md)
- [C++ Guide](../guide/cpp/index.md)
- [C# Guide](../guide/csharp/index.md)
- [Swift Guide](../guide/swift/index.md)
## Native Mode
Use native mode only when every reader and writer is the same runtime family. Native mode supports broader language-specific object models than portable xlang mappings and is optimized for the owning runtime.
Java and Python native modes are first-class same-language entry points. Use Java native mode when replacing JDK serialization, Kryo, FST, Hessian, or Java-only Protocol Buffers payloads. Use Python native mode when replacing `pickle` or `cloudpickle` for Python-only payloads.
Dart, JavaScript/TypeScript, C#, and Swift do not expose native mode.
### Java
```java
Fory fory = Fory.builder()
.withXlang(false)
.requireClassRegistration(true)
.build();
```
Register Java classes and use `serialize` / `deserialize` as usual. See the [Java Guide](../guide/java/index.md) for Java object hooks, `Externalizable`, dynamic object graphs, object copy, and Java native-mode zero-copy buffers.
### Python
```python
import pyfory
fory = pyfory.Fory(xlang=False, ref=False, strict=True)
```
Register Python classes and use `serialize` / `deserialize` as usual. See the [Python Guide](../guide/python/index.md) for native-mode pickle replacement behavior and security settings.
### Go
```go
f := fory.New(fory.WithXlang(false))
```
Use native mode for Go-only structs, pointers, interfaces, and Go-specific type behavior. See the [Go Guide](../guide/go/index.md) for struct tags and native-mode configuration.
### Rust
```rust
let mut fory = Fory::builder().xlang(false).build();
```
Use native mode for Rust-only payloads that rely on Rust-specific object behavior. See the [Rust Guide](../guide/rust/index.md) for derive, references, and supported types.
### C++
```cpp
auto fory = Fory::builder().xlang(false).build();
```
Use native mode for C++-only traffic that does not need portable xlang type mappings. See the [C++ Guide](../guide/cpp/index.md) for `FORY_STRUCT`, configuration, and schema metadata.
### Scala
```scala
val fory = ForyScala.builder()
.withXlang(false)
.build()
```
Use native mode for Scala/JVM-only traffic that needs Scala case classes, collections, tuples, options, or enums on the JVM runtime path. See the [Scala Guide](../guide/scala/index.md).
### Kotlin
```kotlin
val fory = ForyKotlin.builder()
.withXlang(false)
.requireClassRegistration(true)
.buildThreadSafeFory()
```
Use native mode for Kotlin/JVM-only traffic that needs Kotlin data classes, nullable types, ranges, unsigned values, or Kotlin collections on the JVM runtime path. See the [Kotlin Guide](../guide/kotlin/index.md).
## Row Format Encoding
Row format provides zero-copy random access to serialized data, making it ideal for analytics workloads and data processing pipelines.
### Java
```java
import org.apache.fory.format.*;
import java.util.*;
import java.util.stream.*;
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;
// Serialize to row format (can be zero-copy read by Python)
BinaryRow binaryRow = encoder.toRow(foo);
// Deserialize entire object
Foo newFoo = encoder.fromRow(binaryRow);
// Zero-copy access to nested fields without full deserialization
BinaryArray binaryArray2 = binaryRow.getArray(1); // Access f2 field
BinaryArray binaryArray4 = binaryRow.getArray(3); // Access f4 field
BinaryRow barStruct = binaryArray4.getStruct(10); // Access 11th Bar element
long value = barStruct.getArray(1).getInt64(5); // Access nested value
// Partial deserialization
RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class);
Bar newBar = barEncoder.fromRow(barStruct);
Bar newBar2 = barEncoder.fromRow(binaryArray4.getStruct(20));
```
### Python
```python
from dataclasses import dataclass
from typing import List, Dict
import pyarrow as pa
import pyfory
@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)]
)
# Serialize to row format
binary: bytes = encoder.to_row(foo).to_bytes()
# Zero-copy random access without full deserialization
foo_row = pyfory.RowData(encoder.schema, binary)
print(foo_row.f2[100000]) # Access element directly
print(foo_row.f4[100000].f1) # Access nested field
print(foo_row.f4[200000].f2[5]) # Access deeply nested field
```
For more details on row format, see [Java Row Format Guide](../guide/java/row-format.md) or [Python Row Format Guide](../guide/python/row-format.md).