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.
- JIT Code Generation: Highly-extensible JIT framework generates serializer code at runtime using async multi-threaded compilation, delivering 20-170x speedup through:
- Inlining variables to reduce memory access
- Inlining method calls to eliminate virtual dispatch overhead
- Minimizing conditional branching
- Eliminating hash lookups
- Zero-Copy: Direct memory access without intermediate buffer copies; row format supports random access and partial serialization
- Variable-Length Encoding: Optimized compression for integers, longs
- Meta Sharing: Cached class metadata reduces redundant type information
- SIMD Acceleration: Java Vector API support for array operations (Java 16+)
- 100% JDK Serialization Compatible: Supports
writeObject/readObject/writeReplace/readResolve/readObjectNoData/Externalizable - Java 8-24 Support: Works across all modern Java versions including Java 17+ records
- GraalVM Native Image: AOT compilation support without reflection configuration
- Reference Tracking: Automatic handling of shared and circular references
- Schema Evolution: Forward/backward compatibility for class schema changes
- Polymorphism: Full support for inheritance hierarchies and interfaces
- Deep Copy: Efficient deep cloning of complex object graphs with reference preservation
- Security: Class registration and configurable deserialization policies
| Topic | Description | Source Doc Link | Website Doc Link |
|---|---|---|---|
| Java Serialization | Comprehensive usage guide | java_serialization_guide.md | Java Serialization Guide |
| GraalVM Native Image | Native image support | graalvm_guide.md | GraalVM Guide |
| 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>0.15.0</version>
</dependency>
<!-- Optional: Row format support -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-format</artifactId>
<version>0.15.0</version>
</dependency>
<!-- Optional: Serializers for Protobuf data -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-extensions</artifactId>
<version>0.15.0</version>
</dependency>
<!-- Optional: SIMD acceleration (Java 16+) -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-simd</artifactId>
<version>0.15.0</version>
</dependency>dependencies {
implementation 'org.apache.fory:fory-core:0.15.0'
// Optional modules
implementation 'org.apache.fory:fory-format:0.15.0'
implementation 'org.apache.fory:fory-simd:0.15.0'
implementation 'org.apache.fory:fory-extensions:0.15.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)
Fory fory = Fory.builder()
.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 Fory instance
private static final ThreadSafeFory fory = Fory.builder().buildThreadSafeFory();
static {
fory.register(MyClass.class);
}
// Use in multiple threads
byte[] bytes = fory.serialize(object);
Object result = fory.deserialize(bytes);Enable schema compatibility mode to support forward and backward compatibility when your class definitions change over time:
// Enable forward/backward compatibility
Fory fory = Fory.builder()
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.build();
// Serialization and deserialization can use different class versions
// New fields will be ignored, missing fields will use default valuesEnable 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()
.withRefTracking(true)
.build();
// Serialize complex object graphs
GraphNode node = new GraphNode();
node.next = node; // Circular reference
byte[] bytes = fory.serialize(node);Use XLANG mode to serialize data that can be deserialized by other languages (Python, Rust, Go, etc.):
// Use XLANG mode for cross-language compatibility
Fory fory = Fory.builder()
.withLanguage(Language.XLANG)
.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()
// Language mode: JAVA (fastest) or XLANG (cross-language)
.withLanguage(Language.JAVA)
// Reference tracking for circular/shared references
.withRefTracking(true)
// Schema evolution mode
.withCompatibleMode(CompatibleMode.COMPATIBLE)
// 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 Java Serialization Guide for detailed configuration options.
Fory fully supports JDK serialization APIs with 100x better performance. You can use standard Java serialization methods and Fory will handle them automatically:
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()
.withLanguage(Language.JAVA)
.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:
- Zero-Copy Random Access: Read individual fields without deserializing entire objects
- Partial Serialization: Skip unnecessary fields during serialization
- Cross-Language Compatible: Row format data can be read by Python, C++
- Apache Arrow Integration: Convert row format to/from Arrow RecordBatch for 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 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()
.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-appSee GraalVM Guide 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- Reuse Fory Instances: Creating Fory is expensive; reuse instances across serializations
- Enable Compression: For numeric-heavy data, enable int/long compression
- Disable Reference Tracking: If no circular references exist, disable tracking for better performance
- Use Java Mode: Use
Language.JAVAinstead ofLanguage.XLANGwhen cross-language support isn't needed. Java mode reduces type metadata overhead and supports more Java-native types not available in xlang mode - Warm Up: Allow JIT compilation to complete before benchmarking
- Register Classes: Class registration reduces metadata overhead
- Use SIMD: Enable array compression on Java 16+ for numeric arrays
See CONTRIBUTING.md for development guidelines.
Licensed under the Apache License 2.0.