Skip to main content
Version: 1.5.0

Xlang Serialization

Apache Fory™ supports seamless data exchange across Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin.

Create an Xlang Fory Instance

Rust defaults to xlang mode with compatible schema evolution. Set the mode explicitly in xlang examples:

use fory::Fory;

// Use xlang mode
let mut fory = Fory::builder().xlang(true).build();

// Register types with consistent IDs across languages
fory.register::<MyStruct>(100)?;

// Or, on a different Fory instance, use name-based registration
// fory.register_by_name::<MyStruct>("com.example.MyStruct")?;

Type Registration for Xlang

Register by ID

For fast, compact serialization with consistent IDs across languages:

let mut fory = Fory::builder().xlang(true).build();

fory.register::<User>(100)?; // Same ID in Java, Python, etc.

Register by Name

For more flexible type naming:

fory.register_by_name::<User>("com.example.User")?;

Xlang Example

Rust (Serializer)

use fory::Fory;
use fory::ForyStruct;

#[derive(ForyStruct)]
struct Person {
name: String,
age: i32,
}

let mut fory = Fory::builder().xlang(true).build();

fory.register::<Person>(100)?;

let person = Person {
name: "Alice".to_string(),
age: 30,
};

let bytes = fory.serialize(&person)?;
// bytes can be deserialized by Java, Python, etc.

Third-Party Rust Types

An external structural serializer gives a third-party Rust type the same xlang schema as an equivalent local derive:

#[derive(ForyStruct)]
#[fory(target = third_party::User)]
struct UserSerializer {
name: String,
age: u32,
}

let mut fory = Fory::builder().xlang(true).build();
fory.register::<UserSerializer>(100)?;

let bytes = fory.serialize_with::<UserSerializer>(&user)?;

Container roots compose with carrier serializers and keep the ordinary xlang LIST, MAP, tuple, or array representation:

use fory::VecSerializer;

let bytes =
fory.serialize_with::<VecSerializer<UserSerializer>>(&users)?;

Only xlang-representable schemas are accepted. A native Rust enum variant with multiple tuple or named fields is supported with xlang(false), but its serializer registration is rejected in xlang mode. See External-Type Serialization.

Dynamic Rust Carriers

Box<dyn Any>, Rc<dyn Any>, Arc<dyn Any + Send + Sync>, and application dyn Trait carriers can be used in xlang mode when every selected concrete target has an xlang-compatible structural or EXT identity. Fory writes the concrete registered target identity; the Rust trait or erased-carrier identity does not appear on the wire.

Java (Deserializer)

import org.apache.fory.*;
import org.apache.fory.config.*;

public class Person {
public String name;
public int age;
}

Fory fory = Fory.builder()
.withXlang(true)
.withRefTracking(true)
.build();

fory.register(Person.class, 100); // Same ID as Rust

Person person = (Person) fory.deserialize(bytesFromRust);

Python (Deserializer)

import pyfory
from dataclasses import dataclass

@dataclass
class Person:
name: str
age: pyfory.Int32

fory = pyfory.Fory(xlang=True, ref=True)
fory.register_type(Person, type_id=100) # Same ID as Rust

person = fory.deserialize(bytes_from_rust)

Type Mapping

See xlang_type_mapping.md for complete type mapping across languages.

Common Type Mappings

RustJavaPython
i32intint32
i64longint64
f32floatfloat32
f64doublefloat64
Float16Float16float16
BFloat16BFloat16bfloat16
StringStringstr
Vec<T>List<T>List[T]
Vec<Float16>Float16ListFloat16Array
Vec<BFloat16>BFloat16ListBFloat16Array
[Float16; N]Float16ListFloat16Array
[BFloat16; N]BFloat16ListBFloat16Array
HashMap<K,V>Map<K,V>Dict[K,V]
Option<T>nullable TOptional[T]

Lists and Dense Arrays

Rust Vec<T> maps to Fory list<T> by default for manual structs. Use an explicit array field attribute when the schema is dense array<T>.

Fory schemaRust carrier and metadata
list<int32>Vec<i32>
array<bool>#[fory(array)] Vec<bool>
array<int8>#[fory(array)] Vec<i8>
array<int16>#[fory(array)] Vec<i16>
array<int32>#[fory(array)] Vec<i32>
array<int64>#[fory(array)] Vec<i64>
array<uint8>#[fory(array)] Vec<u8>
array<uint16>#[fory(array)] Vec<u16>
array<uint32>#[fory(array)] Vec<u32>
array<uint64>#[fory(array)] Vec<u64>
array<float16>#[fory(array)] Vec<Float16>
array<bfloat16>#[fory(array)] Vec<BFloat16>
array<float32>#[fory(array)] Vec<f32>
array<float64>#[fory(array)] Vec<f64>

Best Practices

  1. Use consistent type IDs across all languages
  2. Keep compatible mode for schema evolution
  3. Register all types before serialization
  4. Test cross-language compatibility during development

See Also