Apache Fory™ Java

Maven Version Java Version License

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.

Features

🚀 High Performance

  • 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+)

🔧 Drop-in Replacement

  • 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

🔄 Advanced Features

  • 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

Documentation

TopicDescriptionSource Doc LinkWebsite Doc Link
Java SerializationComprehensive usage guidejava_serialization_guide.mdJava Serialization Guide
GraalVM Native ImageNative image supportgraalvm_guide.mdGraalVM Guide
Java Serialization SpecProtocol specificationjava_serialization_spec.mdJava Serialization Spec

Modules

ModuleDescriptionMaven Artifact
fory-coreCore serialization engineorg.apache.fory:fory-core
fory-formatRow format and Apache Arrow supportorg.apache.fory:fory-format
fory-simdSIMD-accelerated array compressionorg.apache.fory:fory-simd
fory-extensionsProtobuf support and meta compressionorg.apache.fory:fory-extensions
fory-test-coreTesting utilities and data generatorsorg.apache.fory:fory-test-core

Installation

Maven

<dependency>
  <groupId>org.apache.fory</groupId>
  <artifactId>fory-core</artifactId>
  <version>0.13.1</version>
</dependency>

<!-- Optional: Row format support -->
<dependency>
  <groupId>org.apache.fory</groupId>
  <artifactId>fory-format</artifactId>
  <version>0.13.1</version>
</dependency>

<!-- Optional: Serializers for Protobuf data -->
<dependency>
  <groupId>org.apache.fory</groupId>
  <artifactId>fory-extensions</artifactId>
  <version>0.13.1</version>
</dependency>

<!-- Optional: SIMD acceleration (Java 16+) -->
<dependency>
  <groupId>org.apache.fory</groupId>
  <artifactId>fory-simd</artifactId>
  <version>0.13.1</version>
</dependency>

Gradle

dependencies {
    implementation 'org.apache.fory:fory-core:0.13.1'
    // Optional modules
    implementation 'org.apache.fory:fory-format:0.13.1'
    implementation 'org.apache.fory:fory-simd:0.13.1'
    implementation 'org.apache.fory:fory-extensions:0.13.1'
}

Quick Start

Basic Usage

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);

Thread-Safe Usage

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);

Schema Evolution

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 values

Reference Tracking

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()
  .withRefTracking(true)
  .build();

// Serialize complex object graphs
GraphNode node = new GraphNode();
node.next = node;  // Circular reference
byte[] bytes = fory.serialize(node);

Cross-Language Serialization

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);

Configuration Options

ForyBuilder Options

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.

Advanced Features

JDK Serialization Compatibility

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
  }
}

Deep Copy

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);

Row Format

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.

Array Compression (Java 16+)

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);

GraalVM Native Image

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 Guide for details.

Development

Building

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

Testing

# 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

Code Quality

# Format code
mvn -T16 spotless:apply

# Check code style
mvn -T16 checkstyle:check

Performance Tips

  1. Reuse Fory Instances: Creating Fory is expensive; reuse instances across serializations
  2. Enable Compression: For numeric-heavy data, enable int/long compression
  3. Disable Reference Tracking: If no circular references exist, disable tracking for better performance
  4. Use Java Mode: Use Language.JAVA instead of Language.XLANG when cross-language support isn't needed. Java mode reduces type metadata overhead and supports more Java-native types not available in xlang mode
  5. Warm Up: Allow JIT compilation to complete before benchmarking
  6. Register Classes: Class registration reduces metadata overhead
  7. Use SIMD: Enable array compression on Java 16+ for numeric arrays

Contributing

See CONTRIBUTING.md for development guidelines.

License

Licensed under the Apache License 2.0.