Apache Fory™ Java provides blazingly-fast serialization for the Java ecosystem, delivering up to 170x performance improvement over traditional frameworks through JIT compilation and zero-copy techniques.
writeObject/readObject/writeReplace/readResolve/readObjectNoData/Externalizable| Topic | Description | Source Doc Link | Website Doc Link |
|---|---|---|---|
| Java Guide | Java xlang and native mode usage | docs/guide/java | Java Guide |
| GraalVM Native Image | Native image support | graalvm-support.md | GraalVM Support |
| Java Serialization Spec | 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 | Core serialization engine | org.apache.fory:fory-core |
| fory-format | Row format and Apache Arrow support | org.apache.fory:fory-format |
| fory-simd | SIMD-accelerated array compression | org.apache.fory:fory-simd |
| fory-extensions | Protobuf support and meta compression | org.apache.fory:fory-extensions |
| fory-test-core | Testing utilities and data generators | org.apache.fory:fory-test-core |
<dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-core</artifactId> <version>1.0.0</version> </dependency> <!-- Optional: Row format support --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-format</artifactId> <version>1.0.0</version> </dependency> <!-- Optional: Serializers for Protobuf data --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-extensions</artifactId> <version>1.0.0</version> </dependency> <!-- Optional: SIMD acceleration (Java 16+) --> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-simd</artifactId> <version>1.0.0</version> </dependency>
dependencies { implementation 'org.apache.fory:fory-core:1.0.0' // Optional modules implementation 'org.apache.fory:fory-format:1.0.0' implementation 'org.apache.fory:fory-simd:1.0.0' implementation 'org.apache.fory:fory-extensions:1.0.0' }
Create a Fory instance, register your classes, and start serializing objects. Remember to reuse the Fory instance for optimal performance:
import org.apache.fory.*; import org.apache.fory.config.*; // 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 your classes fory.register(MyClass.class); // Serialize MyClass object = new MyClass(); byte[] bytes = fory.serialize(object); // Deserialize MyClass result = (MyClass) fory.deserialize(bytes);
For multi-threaded environments, use ThreadSafeFory which maintains a pool of Fory instances:
import org.apache.fory.*; import org.apache.fory.config.*; // Create thread-safe xlang Fory instance private static final ThreadSafeFory fory = Fory.builder().withXlang(true).buildThreadSafeFory(); static { fory.register(MyClass.class); } // 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();
Xlang mode enables compatible schema evolution by default. In native mode, enable compatible mode when your class definitions change over time:
Fory fory = Fory.builder().withXlang(false) .withCompatible(true) .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) // Schema evolution mode. Xlang already enables compatible mode by default. .withCompatible(true) // 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:
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);
Fory provides a cache-friendly binary row format optimized for random access and analytics:
import org.apache.fory.format.encoder.*; import org.apache.fory.format.row.*; public class Bar { String f1; List<Long> f2; } public class Foo { int f1; List<Integer> f2; Map<String, Integer> f3; List<Bar> f4; } // Create row encoder RowEncoder<Foo> encoder = Encoders.bean(Foo.class); // Serialize to row format Foo foo = new Foo(); foo.f1 = 10; foo.f2 = IntStream.range(0, 1000).boxed().collect(Collectors.toList()); BinaryRow binaryRow = encoder.toRow(foo); // Zero-copy random access to fields BinaryArray f2Array = binaryRow.getArray(1); // Access f2 without deserializing entire object BinaryArray f4Array = binaryRow.getArray(3); // Access f4 // Zero-copy access nested fields BinaryRow barStruct = f4Array.getStruct(10); // Get 11th element long value = barStruct.getArray(1).getInt64(5); // Access nested field // Partial deserialization RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class); Bar partialBar = barEncoder.fromRow(barStruct); // Deserialize only one Bar object // Full deserialization Foo deserializedFoo = encoder.fromRow(binaryRow);
See the Java row-format guide for more details.
Use SIMD-accelerated compression for integer and long arrays to reduce memory usage when array elements have small values:
import org.apache.fory.simd.*; 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);
Fory supports GraalVM native image through code generation, eliminating the need for reflection configuration. 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
withXlang(false). Native mode reduces type metadata overhead and supports more Java-native types not available in xlang modeSee CONTRIBUTING.md for development guidelines.
Licensed under the Apache License 2.0.