跨语言序列化
本页介绍如何使用 Fory 在 C++ 和其他语言之间进行跨语言序列化。
概述
Apache Fory™ 支持在 C++、Java、Python、Go、Rust 和 JavaScript 之间无缝交换数据。xlang(跨语言)模式确保所有支持语言之间的二进制兼容性。
启用跨语言模式
#include "fory/serialization/fory.h"
using namespace fory::serialization;
auto fory = Fory::builder()
.xlang(true) // 启用跨语言模式
.build();
跨语言示例
C++ 生产者
#include "fory/serialization/fory.h"
#include <fstream>
using namespace fory::serialization;
struct Message {
std::string topic;
int64_t timestamp;
std::map<std::string, std::string> headers;
std::vector<uint8_t> payload;
bool operator==(const Message &other) const {
return topic == other.topic && timestamp == other.timestamp &&
headers == other.headers && payload == other.payload;
}
};
FORY_STRUCT(Message, topic, timestamp, headers, payload);
int main() {
auto fory = Fory::builder().xlang(true).build();
fory.register_struct<Message>(100);
Message msg{
"events.user",
1699999999000,
{{"content-type", "application/json"}},
{'h', 'e', 'l', 'l', 'o'}
};
auto result = fory.serialize(msg);
if (result.ok()) {
auto bytes = std::move(result).value();
// 写入文件、通过网络发送等
std::ofstream file("message.bin", std::ios::binary);
file.write(reinterpret_cast<const char*>(bytes.data()), bytes.size());
}
return 0;
}
Java 消费者
import org.apache.fory.Fory;
import org.apache.fory.config.Language;
public class Message {
public String topic;
public long timestamp;
public Map<String, String> headers;
public byte[] payload;
}
public class Consumer {
public static void main(String[] args) throws Exception {
Fory fory = Fory.builder()
.withLanguage(Language.XLANG)
.build();
fory.register(Message.class, 100); // 与 C++ 相同的 ID
byte[] bytes = Files.readAllBytes(Path.of("message.bin"));
Message msg = (Message) fory.deserialize(bytes);
System.out.println("Topic: " + msg.topic);
System.out.println("Timestamp: " + msg.timestamp);
}
}
Python 消费者
import pyfory
class Message:
topic: str
timestamp: int
headers: dict[str, str]
payload: bytes
fory = pyfory.Fory()
fory.register(Message, type_id=100) # 与 C++ 相同的 ID
with open("message.bin", "rb") as f:
data = f.read()
msg = fory.deserialize(data)
print(f"Topic: {msg.topic}")
print(f"Timestamp: {msg.timestamp}")
类型映射
基本类型
| C++ 类型 | Java 类型 | Python 类型 | Go 类型 | Rust 类型 |
|---|---|---|---|---|
bool | boolean | bool | bool | bool |
int8_t | byte | int | int8 | i8 |
int16_t | short | int | int16 | i16 |
int32_t | int | int | int32 | i32 |
int64_t | long | int | int64 | i64 |
float | float | float | float32 | f32 |
double | double | float | float64 | f64 |
字符串类型
| C++ 类型 | Java 类型 | Python 类型 | Go 类型 | Rust 类型 |
|---|---|---|---|---|
std::string | String | str | string | String |
集合类型
| C++ 类型 | Java 类型 | Python 类型 | Go 类型 |
|---|---|---|---|
std::vector<T> | List<T> | list | []T |
std::set<T> | Set<T> | set | map[T]struct{} |
std::map<K,V> | Map<K,V> | dict | map[K]V |
时间类型
| C++ 类型 | Java 类型 | Python 类型 | Go 类型 |
|---|---|---|---|
Timestamp | Instant | datetime | time.Time |
Duration | Duration | timedelta | time.Duration |
LocalDate | LocalDate | datetime.date | time.Time |
字段顺序要求
关键: 字段将按照其 snake_cased 字段名排序,转换后的名称必须在各语言之间保持一致
C++
struct Person {
std::string name; // 字段 0
int32_t age; // 字段 1
std::string email; // 字段 2
};
FORY_STRUCT(Person, name, age, email); // 顺序很重要!
Java
public class Person {
public String name; // 字段 0
public int age; // 字段 1
public String email; // 字段 2
}
Python
class Person:
name: str # 字段 0
age: int # 字段 1
email: str # 字段 2
类型 ID 一致性
所有语言必须使用相同的类型 ID:
// C++
fory.register_struct<Person>(100);
fory.register_struct<Address>(101);
fory.register_struct<Order>(102);
// Java
fory.register(Person.class, 100);
fory.register(Address.class, 101);
fory.register(Order.class, 102);
# Python
fory.register(Person, type_id=100)
fory.register(Address, type_id=101)
fory.register(Order, type_id=102)
Compatible 模式
用于跨语言边界的 schema 演化:
// 使用 compatible 模式的 C++
auto fory = Fory::builder()
.xlang(true)
.compatible(true) // 启用 schema 演化
.build();
Compatible 模式允许:
- 添加新字段(带默认值)
- 删除未使用的字段
- 重排字段顺序