Apache Fory™ Java provides high-performance binary object serialization, a cross-language random-access row format, and JSON serialization for the Java ecosystem.
| Format | Use it when | Module | Guide |
|---|---|---|---|
| Binary Object Serialization | You need compact object graphs in Java native mode or across supported languages | fory-core | Java guide |
| Row Format | You need zero-copy random access, partial reads, or Arrow integration | fory-format | Row-format guide |
| Fory JSON | You need high-throughput standard JSON for Java applications | fory-json | Fory JSON guide |
Keep all Fory modules in one application on the same version.
Externalizable, and deep copy.ForyJson instance and reuse it across threads.fory-core and fory-json support Java 8 and later; Java records require Java 17 or later.fory-format targets Java 11 and later.fory-core and fory-json run on standard JDKs, GraalVM native images, and Android. Optional SIMD array acceleration in fory-core uses the Java Vector API on Java 16 and later.| Topic | Description | Source Doc Link | Website Doc Link |
|---|---|---|---|
| Java Guide | Binary xlang and native mode usage | docs/guide/java | Java Guide |
| Row Format | Random access and Arrow integration | row-format.md | Row Format |
| Fory JSON | JSON usage, object mapping, and configuration | json-support.md | Fory JSON |
| GraalVM Native Image | Native image support | graalvm-support.md | GraalVM Support |
| Java Serialization Spec | Binary protocol specification | java_serialization_spec.md | Java Serialization Spec |
| Java Benchmarks | Performance data and plots | java/README.md | Java Benchmarks |
| Module | Description | Maven Artifact |
|---|---|---|
| fory-core | Binary native and xlang serialization | org.apache.fory:fory-core |
| fory-format | Row format and Apache Arrow support | org.apache.fory:fory-format |
| fory-json | High-performance JSON serialization framework | org.apache.fory:fory-json |
| fory-extensions | Protobuf support and metadata compression | org.apache.fory:fory-extensions |
| fory-test-core | Testing utilities and data generators | org.apache.fory:fory-test-core |
Add only the artifacts required by your chosen formats and keep their versions aligned. fory-json includes fory-core transitively.
<!-- Binary object serialization --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-core</artifactId> <version>1.4.0</version> </dependency> <!-- Row format --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-format</artifactId> <version>1.4.0</version> </dependency> <!-- JSON serialization --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-json</artifactId> <version>1.4.0</version> </dependency> <!-- Optional: Serializers for Protobuf data --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-extensions</artifactId> <version>1.4.0</version> </dependency>
dependencies { // Binary object serialization implementation 'org.apache.fory:fory-core:1.4.0' // Row format implementation 'org.apache.fory:fory-format:1.4.0' // JSON serialization implementation 'org.apache.fory:fory-json:1.4.0' // Optional: Protobuf serializers and metadata compression implementation 'org.apache.fory:fory-extensions:1.4.0' }
On JDK25+, open java.lang.invoke to Fory. Use ALL-UNNAMED when Fory is on the classpath:
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
Use the Fory core module name when Fory is on the module path:
--add-opens=java.base/java.lang.invoke=org.apache.fory.core
Create a Fory instance, register your classes, and start serializing objects. Remember to reuse the Fory instance for optimal performance:
import org.apache.fory.Fory; // Create Fory instance (should be reused). Java defaults to xlang mode with // compatible schema evolution. Fory fory = Fory.builder() .withXlang(true) .requireClassRegistration(true) .build(); // Register the same type identity on every xlang peer fory.register(MyClass.class, "example.MyClass"); // Serialize MyClass object = new MyClass(); byte[] bytes = fory.serialize(object); // Deserialize MyClass result = fory.deserialize(bytes, MyClass.class);
For multi-threaded environments, use ThreadSafeFory which maintains a pool of Fory instances:
import org.apache.fory.Fory; import org.apache.fory.ThreadSafeFory; // Create thread-safe xlang Fory instance private static final ThreadSafeFory fory = Fory.builder() .withXlang(true) .requireClassRegistration(true) .buildThreadSafeFory(); static { fory.register(MyClass.class, "example.MyClass"); } // Use in multiple threads byte[] bytes = fory.serialize(object); Object result = fory.deserialize(bytes);
Use native mode for Java-only payloads when you need JVM-specific object behavior such as JDK serialization hooks, Externalizable, broader object graph support, or a replacement for JDK serialization, Kryo, FST, Hessian, or Java-only Protocol Buffers payloads:
Fory fory = Fory.builder() .withXlang(false) .requireClassRegistration(true) .build();
Compatible mode is the default for both xlang and native mode. Keep that default when your class definitions change over time:
Fory fory = Fory.builder().withXlang(false) .build(); // Serialization and deserialization can use different class versions // New fields will be ignored, missing fields will use default values
Enable reference tracking to properly handle shared references and circular dependencies in your object graphs:
// Enable reference tracking for circular/shared references Fory fory = Fory.builder().withXlang(false) .withRefTracking(true) .build(); // Serialize complex object graphs GraphNode node = new GraphNode(); node.next = node; // Circular reference byte[] bytes = fory.serialize(node);
Use xlang mode, the Java default, to serialize data that can be deserialized by other languages (Python, Rust, Go, etc.):
Fory fory = Fory.builder() .withXlang(true) .withRefTracking(true) .build(); // Register with cross-language type id/name fory.register(MyClass.class, 1); // fory.register(MyClass.class, "com.example.MyClass"); // Bytes can be deserialized by Python, Go, etc. byte[] bytes = fory.serialize(object);
Configure Fory with various options to suit your specific use case:
Fory fory = Fory.builder() // Native mode for Java-only payloads. Omit this for xlang payloads. .withXlang(false) // Reference tracking for circular/shared references .withRefTracking(true) // Compatible schema evolution is enabled by default. // Compression options .withIntCompressed(true) .withLongCompressed(true) .withStringCompressed(false) // Security options .requireClassRegistration(true) .withMaxDepth(50) // Performance options .withCodeGen(true) .withAsyncCompilation(true) // Class loader .withClassLoader(classLoader) .build();
See the Java guide for detailed configuration options.
In native mode, Fory supports JDK serialization APIs with much better performance. Use native mode when replacing Java-only JDK serialization, Kryo, FST, Hessian, or Protocol Buffers payloads:
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class MyClass implements Serializable { private void writeObject(ObjectOutputStream out) throws IOException { // Custom serialization logic } private void readObject(ObjectInputStream in) throws IOException { // Custom deserialization logic } private Object writeReplace() { // Return replacement object } private Object readResolve() { // Return resolved object } }
Enable reference tracking during deep copy to preserve object identity and handle circular references correctly:
Fory fory = Fory.builder() .withXlang(false) .withRefCopy(true) .build(); MyClass original = new MyClass(); MyClass copy = fory.copy(original);
Use width compression for integer and long arrays to reduce serialized size when array elements have small values. JDK 8 through 15 use scalar range analysis; JDK 16 and later automatically select the Vector API implementation from the multi-release JAR.
import org.apache.fory.serializer.CompressedArraySerializers; Fory fory = Fory.builder().withXlang(false) .withIntArrayCompressed(true) .withLongArrayCompressed(true) .build(); // Register compressed array serializers CompressedArraySerializers.registerSerializers(fory); // Arrays with small values are automatically compressed int[] data = new int[1000000]; byte[] bytes = fory.serialize(data);
On JDK 16 or later, resolve the incubator Vector API module when starting the application:
java --add-modules=jdk.incubator.vector ...
Fory or ThreadSafeFory instances instead of rebuilding runtime state for each operation.Fory row format is a cache-friendly binary format for random access and analytics. It can read fields, arrays, and nested values without rebuilding the complete object.
import org.apache.fory.format.encoder.Encoders; import org.apache.fory.format.encoder.RowEncoder; import org.apache.fory.format.row.ArrayData; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.format.type.Schema; public final class RowExample { public static final class User { public int id; public String name; public int[] scores; } public static void main(String[] args) { 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); System.out.println(name + ": " + secondScore); } }
See the Java row-format guide for nested structs, arrays, maps, partial deserialization, and Arrow integration.
Fory JSON is a thread-safe JSON serialization framework for Java, extensively optimized for maximum performance across JSON encoding, decoding, and Java object mapping.
Build one ForyJson instance and reuse it across threads:
import java.nio.charset.StandardCharsets; import org.apache.fory.json.ForyJson; public final class JsonExample { private static final ForyJson JSON = ForyJson.builder().build(); public static final class User { public long id; public String name; public User() {} public User(long id, String name) { this.id = id; this.name = name; } } public static void main(String[] args) { User input = new User(7, "Alice"); String text = JSON.toJson(input); User fromText = JSON.fromJson(text, User.class); byte[] utf8 = JSON.toJsonBytes(input); User fromUtf8 = JSON.fromJson(utf8, User.class); System.out.println(text); System.out.println(new String(utf8, StandardCharsets.UTF_8)); System.out.println(fromText.name + " / " + fromUtf8.name); } }
Fory JSON supports Java 8 and later on standard JDKs, GraalVM native images, and Android. Java records are supported on Java 17 and later. See the Fory JSON guide for supported types, annotations, custom codecs, security controls, and platform setup.
Fory supports GraalVM Native Image without application reflection configuration. Binary serialization generates serializers while the image is built; the Fory annotation processor generates type-owned execution companions for Fory JSON @JsonType models. Build your native image as follows:
# Generate serializers at build time mvn package -Pnative # Run native image ./target/my-app
See GraalVM Support for details.
All commands must be executed in the java directory:
# Build mvn -T16 clean package # Run tests mvn -T16 test # Install locally mvn -T16 install -DskipTests # Code formatting mvn -T16 spotless:apply # Code style check mvn -T16 checkstyle:check
# Run all tests mvn -T16 test # Run specific test mvn -T16 test -Dtest=MyTestClass#testMethod # Run with specific JDK JAVA_HOME=/path/to/jdk mvn test
# Format code mvn -T16 spotless:apply # Check code style mvn -T16 checkstyle:check
See CONTRIBUTING.md for development guidelines.
Licensed under the Apache License 2.0.