docs(cpp): clarify MSVC preprocessor requirement (#3695) ## Why? ## What does this PR do? ## Related issues Closes #3693 ## AI Contribution Checklist - [ ] Substantial AI assistance was used in this PR: `yes` / `no` - [ ] If `yes`, I included a completed [AI Contribution Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs) in this PR description and the required `AI Usage Disclosure`. - [ ] If `yes`, my PR description includes the required `ai_review` summary and screenshot evidence of the final clean AI review results from both fresh reviewers on the current PR diff or current HEAD after the latest code changes. ## Does this PR introduce any user-facing change? - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark
Apache Fory™ is a blazingly fast multi-language serialization framework for idiomatic domain objects, schema IDL, and cross-language data exchange.
Fory is built for fast, compact serialization across languages and runtimes. It works with idiomatic objects in each language, supports shared schemas when you need a contract, and preserves object features such as shared and circular references.
Benchmarks show Fory delivering higher throughput and smaller serialized payloads than common serialization frameworks on representative workloads. Java has the broadest comparison set; the other charts show runtime-specific results across supported languages.
Java Benchmarks
In Java serialization benchmarks, Fory reaches up to 170x the throughput of JDK serialization on selected workloads.
Python Benchmarks
Rust Benchmarks
C++ Benchmarks
Go Benchmarks
JavaScript/TypeScript Benchmarks
C# Benchmarks
Swift Benchmarks
Dart Benchmarks
Pick the runtime you use and run the package-manager command, or paste the dependency block into your build file.
Java
Maven:
<dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-core</artifactId> <version>0.17.0</version> </dependency>
Gradle:
implementation "org.apache.fory:fory-core:0.17.0"
Scala
sbt:
libraryDependencies += "org.apache.fory" %% "fory-scala" % "0.17.0"
Kotlin
Gradle:
implementation("org.apache.fory:fory-kotlin:0.17.0")
Maven:
<dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-kotlin</artifactId> <version>0.17.0</version> </dependency>
Python
pip install pyfory
For row-format support:
pip install "pyfory[format]"
Rust
Cargo.toml:
[dependencies] fory = "0.17"
C++
CMake:
include(FetchContent) FetchContent_Declare( fory GIT_REPOSITORY https://github.com/apache/fory.git GIT_TAG v0.17.0 SOURCE_SUBDIR cpp ) FetchContent_MakeAvailable(fory) target_link_libraries(my_app PRIVATE fory::serialization)
Bazel:
# MODULE.bazel bazel_dep(name = "fory", version = "0.17.0") git_override(module_name = "fory", remote = "https://github.com/apache/fory.git", commit = "v0.17.0") # BUILD deps = ["@fory//cpp/fory/serialization:fory_serialization"]
When building C++ with MSVC, enable the conforming preprocessor option /Zc:preprocessor; see the C++ installation guide for setup details.
See the C++ installation guide for complete CMake, Bazel, and source-build details.
Go
go get github.com/apache/fory/go/fory
JavaScript/TypeScript
npm install @apache-fory/core
For the Node.js string fast path:
npm install @apache-fory/core @apache-fory/hps
C#
dotnet add package Apache.Fory --version 0.17.0
Dart
dart pub add fory:^0.17.0 dart pub add dev:build_runner
Swift
Add Fory to Package.swift:
dependencies: [ .package(url: "https://github.com/apache/fory.git", exact: "0.17.0") ], targets: [ .target( name: "YourTarget", dependencies: [.product(name: "Fory", package: "fory")] ) ]
See the Swift guide for generated serializer setup.
Development From Source
See docs/DEVELOPMENT.md.
Snapshots for Java, Scala, and Kotlin are available from https://repository.apache.org/snapshots/ with the matching -SNAPSHOT version.
| Mode | Use it when | Start here |
|---|---|---|
| Xlang mode | Data crosses language boundaries | Cross-language guide |
| Native mode | Producer and consumer are in the same language | Language guide for your runtime |
| Row format | You need random field access or analytics-style partial reads | Row format spec |
For Java, Scala, Kotlin, Python, C++, Go, and Rust, use native mode for same-language traffic. It avoids xlang‘s cross-language type mapping and metadata constraints, stays closer to each runtime’s native type system, and supports broader language-specific object graphs. Use it when both producer and consumer are in the same runtime family and you want the native object model rather than a portable cross-language schema.
For Java/JVM-only systems, native mode is the replacement path for JDK serialization, Kryo, FST, Hessian, and Java-only Protocol Buffers payloads. For Python-only systems, native mode is the replacement path for pickle and cloudpickle.
Compatible mode is Fory's schema-evolution mode. It writes the metadata readers and writers need to tolerate schema differences. Xlang mode enables compatible mode by default to better handle differences between language type systems. Native mode keeps it off by default for smaller payloads and higher throughput.
Use compatible mode when services deploy independently or when fields may be added or deleted over time. Use schema-consistent mode when writer and reader schemas deploy together and you want the smallest payloads.
For xlang, all peers must agree on type identity. Name-based registration is easier to read in examples. Numeric IDs are smaller and faster, but they require coordination across every reader and writer.
Xlang mode writes the cross-language Fory wire format. Bytes produced by one runtime can be read by another when the runtimes use the same type identity, compatible mode setting, and field schema.
Java
import org.apache.fory.Fory; public class Example { public static class Person { public String name; public 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(); person.name = "Alice"; person.age = 30; byte[] bytes = fory.serialize(person); Person decoded = (Person) fory.deserialize(bytes); System.out.println(decoded.name); } }
Python
from dataclasses import dataclass import pyfory @dataclass class Person: name: str age: pyfory.Int32 fory = pyfory.Fory(xlang=True) fory.register_type(Person, typename="example.Person") data = fory.serialize(Person("Alice", 30)) person = fory.deserialize(data) print(person.name)
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.RegisterStructByName(Person{}, "example.Person"); err != nil {
panic(err)
}
data, _ := f.Serialize(&Person{Name: "Alice", Age: 30})
var person Person
if err := f.Deserialize(data, &person); err != nil {
panic(err)
}
fmt.Println(person.Name)
}
Rust
use fory::{Error, Fory, ForyStruct}; #[derive(ForyStruct, 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 bytes = fory.serialize(&Person { name: "Alice".to_string(), age: 30, })?; let person: Person = fory.deserialize(&bytes)?; println!("{}", person.name); Ok(()) }
C++
#include "fory/serialization/fory.h" #include <cstdint> #include <iostream> #include <string> using namespace fory::serialization; struct Person { std::string name; int32_t age; }; FORY_STRUCT(Person, name, age); int main() { auto fory = Fory::builder().xlang(true).build(); fory.register_struct<Person>("example", "Person"); auto bytes = fory.serialize(Person{"Alice", 30}).value(); Person person = fory.deserialize<Person>(bytes).value(); std::cout << person.name << std::endl; }
JavaScript/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 bytes = serialize({ name: "Alice", age: 30 }); const person = deserialize(bytes); console.log(person.name);
C#
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>("example", "Person"); byte[] bytes = fory.Serialize(new Person { Name = "Alice", Age = 30 }); Person person = fory.Deserialize<Person>(bytes); Console.WriteLine(person.Name);
C# always writes the xlang frame header, so there is no separate xlang builder flag.
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 bytes = fory.serialize(Person() ..name = 'Alice' ..age = 30); final person = fory.deserialize<Person>(bytes); print(person.name); }
Dart uses the xlang wire format directly. Generate the companion file before running:
dart run build_runner build --delete-conflicting-outputs
Swift
import Fory @ForyStruct struct Person { var name: String = "" var age: Int32 = 0 } let fory = Fory() try fory.register(Person.self, namespace: "example", name: "Person") let bytes = try fory.serialize(Person(name: "Alice", age: 30)) let person: Person = try fory.deserialize(bytes) print(person.name)
Scala
import org.apache.fory.scala.ForyScala case class Person(name: String, age: Int) val fory = ForyScala.builder().withXlang(true).build() fory.register(classOf[Person], "example.Person") val bytes = fory.serialize(Person("Alice", 30)) val person = fory.deserialize(bytes).asInstanceOf[Person] println(person.name)
Kotlin
import org.apache.fory.kotlin.ForyKotlin data class Person(val name: String, val age: Int) fun main() { val fory = ForyKotlin.builder().withXlang(true).build() fory.register(Person::class.java, "example.Person") val bytes = fory.serialize(Person("Alice", 30)) val person = fory.deserialize(bytes) as Person println(person.name) }
For shared/circular references, polymorphism, numeric IDs versus names, and type-mapping rules, see the cross-language guide and type mapping specification.
Use native mode when the writer and reader are in the same language. It is optimized for each runtime's native type system and can cover language-specific types, object graphs, and framework-replacement cases that xlang mode keeps out of the portable wire format. The languages below expose an explicit xlang=false or native-mode setting; runtimes without that switch stay on their documented default path.
Choose Java native mode for Java/JVM-only replacements of JDK serialization, Kryo, FST, Hessian, or Java-only Protocol Buffers payloads. Choose Python native mode when replacing pickle or cloudpickle for Python-only payloads.
Keep class/type registration enabled for untrusted input. See the language guides for runtime-specific security and compatibility settings.
Java
Fory fory = Fory.builder() .withXlang(false) .requireClassRegistration(true) .build(); // Register, serialize, and deserialize as in the xlang example above.
Python
fory = pyfory.Fory(xlang=False, ref=True) # Register, serialize, and deserialize as in the xlang example above.
Go
f := fory.New(fory.WithXlang(false)) // Register, serialize, and deserialize as in the xlang example above.
Rust
let mut fory = Fory::builder().xlang(false).build(); // Register, serialize, and deserialize as in the xlang example above.
C++
auto fory = Fory::builder().xlang(false).build(); // Register, serialize, and deserialize as in the xlang example above.
Scala
import org.apache.fory.scala.ForyScala val fory = ForyScala.builder() .withXlang(false) .requireClassRegistration(true) .build() // Register, serialize, and deserialize as in the xlang example above.
Kotlin
import org.apache.fory.kotlin.ForyKotlin val fory = ForyKotlin.builder() .withXlang(false) .requireClassRegistration(true) .build() // Register, serialize, and deserialize as in the xlang example above.
Fory IDL is Fory's schema language for shared data models. It supports references, nullable fields, lists, maps, arrays, enums, messages, and unions, and generates native data structures for supported languages. Use it when multiple languages need one shared contract.
package tree; message TreeNode { string id = 1; string name = 2; list<ref TreeNode> children = 3; ref(weak=true) TreeNode parent = 4; // back-pointer }
See the Fory IDL and compiler guide.
Row format is for random access and partial reads. These examples encode an object with an integer array field, then read one array element from the binary row without rebuilding the object.
Python
from dataclasses import dataclass from typing import List import pyfory @dataclass class User: id: pyfory.Int32 name: str scores: List[pyfory.Int32] encoder = pyfory.encoder(User) binary = encoder.to_row(User(1, "Alice", [98, 100, 95])).to_bytes() row = pyfory.RowData(encoder.schema, binary) print(row.name) print(row.scores[1])
Java
public class User { public int id; public String name; public int[] scores; } RowEncoder<User> encoder = Encoders.bean(User.class); User user = new User(); user.id = 1; user.name = "Alice"; user.scores = new int[] {98, 100, 95}; BinaryRow row = encoder.toRow(user); Schema schema = encoder.schema(); Schema.StringField nameField = schema.stringField("name"); Schema.ArrayField scoresField = schema.arrayField("scores"); String name = nameField.get(row); ArrayData scores = scoresField.get(row); int secondScore = scores.getInt32(1);
For Java imports, nested structs, arrays/maps, Arrow integration, and partial deserialization, see the Java row-format guide, the Python row-format guide, and the row-format specification.
User Guides
| Guide | Source | Website |
|---|---|---|
| Java | docs/guide/java | View |
| Python | docs/guide/python | View |
| Rust | docs/guide/rust | View |
| C++ | docs/guide/cpp | View |
| Go | docs/guide/go | View |
| JavaScript/TypeScript | docs/guide/javascript | View |
| C# | docs/guide/csharp | View |
| Swift | docs/guide/swift | View |
| Dart | docs/guide/dart | View |
| Scala | docs/guide/scala | View |
| Kotlin | docs/guide/kotlin | View |
| Cross-language xlang | docs/guide/xlang | View |
| Schema IDL/compiler | docs/compiler | View |
| GraalVM native image | docs/guide/java/graalvm-support.md | View |
| Development | docs/DEVELOPMENT.md | View |
Specifications
| Specification | Source | Website |
|---|---|---|
| Xlang serialization | xlang_serialization_spec.md | View |
| Java serialization | java_serialization_spec.md | View |
| Row format | row_format_spec.md | View |
| Cross-language mapping | xlang_type_mapping.md | View |
Read CONTRIBUTING.md and docs/DEVELOPMENT.md before sending pull requests. Bug reports, docs fixes, tests, benchmarks, and runtime improvements are welcome.
Apache Fory™ is licensed under the Apache License 2.0.