序列化
本页演示了所有支持语言的跨语言序列化模式示例。在一种语言中序列化的数据可以在任何其他支持的语言中反序列化。
序列化内置类型
常见类型可以自动序列化,无需注册:原始数值类型、字符串、二进制、数组、列表、映射等。
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 可以被其他语言反序列化
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 可以被其他语言反序列化
fory.deserialize(bytes);
}
}
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 可以被其他语言反序列化
new_list = fory.deserialize(data)
object_map = {"k1": "v1", "k2": object_list, "k3": -1}
data = fory.serialize(object_map)
# bytes 可以被其他语言反序列化
new_map = fory.deserialize(data)
print(new_map)
Go
package main
import forygo "github.com/apache/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 可以被其他语言反序列化
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 可以被其他语言反序列化
if err := fory.Unmarshal(bytes, &newValue); err != nil {
panic(err)
}
fmt.Println(newValue)
}
JavaScript
import Fory from "@apache-fory/fory";
/**
* @apache-fory/hps 使用 v8 的 fast-calls-api,可以直接被 jit 调用,
* 确保 Node 版本为 20 或更高。
* 实验性功能,目前无法保证安装成功。
* 如果无法安装该模块,请将其替换为 `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
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);
}
序列化自定义类型
用户定义的类型必须使用 register API 进行注册,以建立不同语言中类型之间的映射关系。请在所有语言中使用一致的类型名称。
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 可以被其他语言反序列化
System.out.println(fory.deserialize(bytes));
}
}
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 类型将被视为 `pyfory.Int64Type`。
# 如 果对等方使用更窄的类型,请使用 `pyfory.Int32Type` 进行类型提示。
f8: int = None
f9: pyfory.Float32Type = None
# float 类型将被视为 `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 可以被其他语言反序列化
print(f.deserialize(data))
Go
package main
import forygo "github.com/apache/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 SomeClass2 struct {
F1 interface{}
F2 map[int8]int32
}
fory := forygo.NewFory()
if err := fory.RegisterTagType("example.SomeClass1", SomeClass1{}); err != nil {
panic(err)
}
if err := fory.RegisterTagType("example.SomeClass2", 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 可以被其他语言反序列化
if err := fory.Unmarshal(bytes, &newValue); err != nil {
panic(err)
}
fmt.Println(newValue)
}
JavaScript
import Fory, { Type, InternalSerializerType } from "@apache-fory/fory";
/**
* @apache-fory/hps 使用 v8 的 fast-calls-api,可以直接被 jit 调用,
* 确保 Node 版本为 20 或更高。
* 实验性功能,目前无法保证安装成功。
* 如果无法安装该模块,请将其替换为 `const hps = null;`
**/
import hps from "@apache-fory/hps";
// 使用 JSON schema 描述数据结构
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
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);
}
序列化共享引用和循环引用
共享引用和循环引用可以自动序列化,不会有重复数据或递归错误。启用引用跟踪即可使用此功能。
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 可以被其他语言反序列化
System.out.println(fory.deserialize(bytes));
}
}
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 可以被其他语言反序列化
print(fory.deserialize(data))
Go
package main
import forygo "github.com/apache/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 {
panic(err)
}
var newValue interface{}
// bytes 可以被其他语言反序列化
if err := fory.Unmarshal(bytes, &newValue); err != nil {
panic(err)
}
fmt.Println(newValue)
}
JavaScript
import Fory, { Type } from "@apache-fory/fory";
/**
* @apache-fory/hps 使用 v8 的 fast-calls-api,可以直接被 jit 调用,
* 确保 Node 版本为 20 或更高。
* 实验性功能,目前无法保证安装成功。
* 如果无法安装该模块,请将其替换为 `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);
Rust
由于所有权限制,Rust 中无法实现循环引用。
另请参阅
- 零拷贝序列化 - 大型数据的带外序列化
- 类型映射 - 跨语言类型映射参考
- 入门指南 - 安装和设置
- Xlang 序列化规范 - 二进制协议详情