tree: 9afe006dcb47c7a2e09a9e020fc0d0f7b20b4dd4
  1. fory-annotation-processor/
  2. fory-core/
  3. fory-extensions/
  4. fory-format/
  5. fory-json/
  6. fory-latest-jdk-tests/
  7. fory-test-core/
  8. fory-testsuite/
  9. checkstyle-suppressions.xml
  10. checkstyle.xml
  11. pom.xml
  12. README.md
java/README.md

Apache Fory™ Java

Maven Version Java Version License

Apache Fory™ Java provides high-performance binary object serialization, a cross-language random-access row format, and JSON serialization for the Java ecosystem.

Choose a Format

FormatUse it whenModuleGuide
Binary Object SerializationYou need compact object graphs in Java native mode or across supported languagesfory-coreJava guide
Row FormatYou need zero-copy random access, partial reads, or Arrow integrationfory-formatRow-format guide
Fory JSONYou need high-throughput standard JSON for Java applicationsfory-jsonFory JSON guide

Keep all Fory modules in one application on the same version.

Features

Binary Object Serialization

  • Generated Codecs: JIT-generated serializers inline data access and reduce virtual dispatch, branching, and metadata lookups on hot paths.
  • Native and Cross-Language Modes: Use Java-native object semantics for Java-only traffic or a portable wire format across supported languages.
  • Object Graph Semantics: Preserve shared and circular references, polymorphism, and schema evolution.
  • Compact Encoding: Variable-length integer encoding, metadata sharing, string compression, and optional numeric-array compression reduce payload size.
  • Java Object Model: Native mode supports ordinary Java classes, records, JDK custom serialization semantics, Externalizable, and deep copy.
  • Security Controls: Class registration, type checking, depth limits, and configurable deserialization policies protect decoding boundaries.

Row Format

  • Zero-Copy Random Access: Read fields and nested values without rebuilding complete objects.
  • Partial Reads: Decode only the data required by an analytics or query path.
  • Apache Arrow Integration: Convert between Fory row data and Arrow data for columnar processing.

Fory JSON

  • Maximum Performance: Optimized readers and writers plus interpreted and runtime-generated codecs keep JSON encoding and decoding fast.
  • Java Object Mapping: Supports ordinary objects, Java 17 records, immutable creator-based classes, common JDK types, generic containers, custom codecs, and annotation-declared polymorphism.
  • Thread-Safe Runtime: Build one immutable ForyJson instance and reuse it across threads.

Platforms

  • 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.

Documentation

TopicDescriptionSource Doc LinkWebsite Doc Link
Java GuideBinary xlang and native mode usagedocs/guide/javaJava Guide
Row FormatRandom access and Arrow integrationrow-format.mdRow Format
Fory JSONJSON usage, object mapping, and configurationjson-support.mdFory JSON
GraalVM Native ImageNative image supportgraalvm-support.mdGraalVM Support
Java Serialization SpecBinary protocol specificationjava_serialization_spec.mdJava Serialization Spec
Java BenchmarksPerformance data and plotsjava/README.mdJava Benchmarks

Modules

ModuleDescriptionMaven Artifact
fory-coreBinary native and xlang serializationorg.apache.fory:fory-core
fory-formatRow format and Apache Arrow supportorg.apache.fory:fory-format
fory-jsonHigh-performance JSON serialization frameworkorg.apache.fory:fory-json
fory-extensionsProtobuf support and metadata compressionorg.apache.fory:fory-extensions
fory-test-coreTesting utilities and data generatorsorg.apache.fory:fory-test-core

Installation

Add only the artifacts required by your chosen formats and keep their versions aligned. fory-json includes fory-core transitively.

Maven

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

Gradle

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

JDK25+

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

Binary Object Serialization

Quick Start

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

Thread-Safe Usage

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

Native Mode

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

Schema Evolution

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

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().withXlang(false)
  .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, 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);

Configuration

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.

JDK Custom Serialization Semantics

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

Deep Copy

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

Array Compression

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

Performance Guidelines

  1. Reuse Fory or ThreadSafeFory instances instead of rebuilding runtime state for each operation.
  2. Register application classes to avoid repeated type metadata and keep type identity explicit.
  3. Use native mode for Java-only payloads; use xlang mode only when payloads must cross language boundaries.
  4. Keep compatible mode enabled when schemas may differ. Disable it only when every reader and writer always uses the same schema.
  5. Disable reference tracking only when shared identity and circular references are not part of the data model.
  6. Enable string, integer, long, or numeric-array compression only after measuring the payload distribution and throughput tradeoff.
  7. Warm up generated serializers before measuring steady-state performance.

Row Format

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

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.

GraalVM Native Image

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.

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

Contributing

See CONTRIBUTING.md for development guidelines.

License

Licensed under the Apache License 2.0.