Apache Fory™ Java provides high-performance binary object serialization, a cross-language random-access row format, and JSON serialization for the Java ecosystem.
| Format | Use it when | Module | Guide |
|---|---|---|---|
| Binary Object Serialization | You need compact object graphs in Java native mode or across supported languages | fory-core |
Java guide |
| Row Format | You need zero-copy random access, partial reads, or Arrow integration | fory-format |
Row-format guide |
| Fory JSON | You need high-throughput standard JSON for Java applications | fory-json |
Fory JSON guide |
Keep all Fory modules in one application on the same version.
- 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.
- 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.
- 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
ForyJsoninstance and reuse it across threads.
fory-coreandfory-jsonsupport Java 8 and later; Java records require Java 17 or later.fory-formattargets Java 11 and later.fory-coreandfory-jsonrun on standard JDKs, GraalVM native images, and Android. Optional SIMD array acceleration infory-coreuses the Java Vector API on Java 16 and later.
| Topic | Description | Source Doc Link | Website Doc Link |
|---|---|---|---|
| Java Guide | Binary xlang and native mode usage | docs/guide/java | Java Guide |
| Row Format | Random access and Arrow integration | row-format.md | Row Format |
| Fory JSON | JSON usage, object mapping, and configuration | json-support.md | Fory JSON |
| GraalVM Native Image | Native image support | graalvm-support.md | GraalVM Support |
| Java Serialization Spec | Binary 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 | Binary native and xlang serialization | org.apache.fory:fory-core |
| fory-format | Row format and Apache Arrow support | org.apache.fory:fory-format |
| fory-json | High-performance JSON serialization framework | org.apache.fory:fory-json |
| fory-extensions | Protobuf support and metadata compression | org.apache.fory:fory-extensions |
| fory-test-core | Testing utilities and data generators | org.apache.fory:fory-test-core |
Add only the artifacts required by your chosen formats and keep their versions
aligned. fory-json includes fory-core transitively.
<!-- Binary object serialization -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-core</artifactId>
<version>1.5.0</version>
</dependency>
<!-- Row format -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-format</artifactId>
<version>1.5.0</version>
</dependency>
<!-- JSON serialization -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-json</artifactId>
<version>1.5.0</version>
</dependency>
<!-- Optional: Serializers for Protobuf data -->
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-extensions</artifactId>
<version>1.5.0</version>
</dependency>dependencies {
// Binary object serialization
implementation 'org.apache.fory:fory-core:1.5.0'
// Row format
implementation 'org.apache.fory:fory-format:1.5.0'
// JSON serialization
implementation 'org.apache.fory:fory-json:1.5.0'
// Optional: Protobuf serializers and metadata compression
implementation 'org.apache.fory:fory-extensions:1.5.0'
}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-UNNAMEDUse the Fory core module name when Fory is on the module path:
--add-opens=java.base/java.lang.invoke=org.apache.fory.coreCreate 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);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);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();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 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().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)
// 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.
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
}
}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);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 ...- Reuse
ForyorThreadSafeForyinstances instead of rebuilding runtime state for each operation. - Register application classes to avoid repeated type metadata and keep type identity explicit.
- Use native mode for Java-only payloads; use xlang mode only when payloads must cross language boundaries.
- Keep compatible mode enabled when schemas may differ. Disable it only when every reader and writer always uses the same schema.
- Disable reference tracking only when shared identity and circular references are not part of the data model.
- Enable string, integer, long, or numeric-array compression only after measuring the payload distribution and throughput tradeoff.
- Warm up generated serializers before measuring steady-state performance.
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 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.
Fory supports GraalVM Native Image without application reflection configuration. Binary
serialization generates serializers while the image is built. Fory JSON discovers reachable
@JsonType and @JsonMixin models directly, without the annotation processor. Interpreted JSON
codecs work by default; return configurations from a reachable @ForyJsonProvider to generate
matching JSON codecs while the image is built. Build your native image as follows:
# Generate serializers at build time
mvn package -Pnative
# Run native image
./target/my-appSee 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:checkSee CONTRIBUTING.md for development guidelines.
Licensed under the Apache License 2.0.