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.