This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git
The following commit(s) were added to refs/heads/main by this push:
new 44cc3b298c π synced local 'docs/guide/' with remote 'docs/guide/'
44cc3b298c is described below
commit 44cc3b298c936e66fdcad65d739f74045e0d81d6
Author: chaokunyang <[email protected]>
AuthorDate: Tue Jul 14 17:05:15 2026 +0000
π synced local 'docs/guide/' with remote 'docs/guide/'
---
docs/guide/java/compression.md | 26 ++++---
docs/guide/java/configuration.md | 4 +-
docs/guide/java/graalvm-support.md | 143 ++++++++++++++++---------------------
3 files changed, 80 insertions(+), 93 deletions(-)
diff --git a/docs/guide/java/compression.md b/docs/guide/java/compression.md
index 587b2c1f7c..43133375c0 100644
--- a/docs/guide/java/compression.md
+++ b/docs/guide/java/compression.md
@@ -49,7 +49,7 @@ If a number is of `long` type but can't be represented by
smaller bytes mostly,
## Array Compression
-Fory supports SIMD-accelerated compression for primitive arrays (`int[]` and
`long[]`) when array values can fit in smaller data types. This feature is
available on Java 16+ and uses the Vector API for optimal performance.
+Fory can compress primitive arrays (`int[]` and `long[]`) when every value
fits in a narrower primitive type. JDK 8 through 15 use scalar range analysis.
On JDK 16 and later, the multi-release `fory-core` JAR automatically selects
the Vector API implementation.
### How Array Compression Works
@@ -76,7 +76,13 @@ Fory fory = Fory.builder()
CompressedArraySerializers.registerSerializers(fory);
```
-Compressed array serializers are included in `fory-core` and use the Java 16+
Vector API when it is available.
+Compressed array serializers are included in `fory-core`. When running on JDK
16 or later, resolve the incubator Vector API module when starting the
application:
+
+```bash
+java --add-modules=jdk.incubator.vector ...
+```
+
+No registration or configuration change is required when moving between the
scalar and Vector implementations. They make the same compression decisions and
use the same serialized format.
## String Compression
@@ -84,18 +90,18 @@ String compression can be enabled via
`ForyBuilder#withStringCompressed(true)`.
## Configuration Summary
-| Option | Description |
Default |
-| ------------------- | --------------------------------------------- |
------- |
-| `compressInt` | Enable int compression | `true`
|
-| `compressLong` | Enable long compression | `true`
|
-| `compressIntArray` | Enable SIMD int array compression (Java 16+) |
`false` |
-| `compressLongArray` | Enable SIMD long array compression (Java 16+) |
`false` |
-| `compressString` | Enable string compression |
`false` |
+| Option | Description | Default |
+| ------------------- | ----------------------------------- | ------- |
+| `compressInt` | Enable int compression | `true` |
+| `compressLong` | Enable long compression | `true` |
+| `compressIntArray` | Enable int array width compression | `false` |
+| `compressLongArray` | Enable long array width compression | `false` |
+| `compressString` | Enable string compression | `false` |
## Performance Considerations
1. **Disable compression for numeric-heavy data**: If your data is mostly
numbers, compression overhead may not be worth it
-2. **Array compression requires Java 16+**: Uses Vector API for SIMD
acceleration
+2. **Array compression implementation is JDK-specific**: JDK 8 through 15 use
scalar range analysis; JDK 16 and later automatically select the Vector API
implementation
3. **Long compression may not help large values**: If most longs can't fit in
smaller representations, disable it
4. **String compression has overhead**: Only enable if strings are highly
compressible
diff --git a/docs/guide/java/configuration.md b/docs/guide/java/configuration.md
index d3a56e5e97..7c4d47c9cb 100644
--- a/docs/guide/java/configuration.md
+++ b/docs/guide/java/configuration.md
@@ -28,8 +28,8 @@ This page documents all configuration options available
through `ForyBuilder`.
| `timeRefIgnored` | Whether to ignore reference tracking
of all time types registered in `TimeSerializers` and subclasses of those types
when ref tracking is enabled. If ignored, ref tracking of every time type can
be enabled by invoking `Fory#registerSerializer(Class, Serializer)`. For
example, `fory.registerSerializer(Date.class, new
DateSerializer(fory.getConfig(), true))`. Note that enabling ref tracking
should happen before serializer codegen of any types which c [...]
| `compressInt` | Enables or disables int compression
for smaller size.
[...]
| `compressLong` | Enables or disables long compression
for smaller size.
[...]
-| `compressIntArray` | Enables or disables SIMD-accelerated
compression for int arrays when values can fit in smaller data types. Requires
Java 16+.
[...]
-| `compressLongArray` | Enables or disables SIMD-accelerated
compression for long arrays when values can fit in smaller data types. Requires
Java 16+.
[...]
+| `compressIntArray` | Enables or disables compression for
int arrays when values are small. When `CompressedArraySerializers` is
explicitly registered, JDK 8 through 15 use scalar width analysis and JDK 16
and later automatically select the Vector API implementation when
`jdk.incubator.vector` is resolved.
[...]
+| `compressLongArray` | Enables or disables compression for
long arrays when values are small. When `CompressedArraySerializers` is
explicitly registered, JDK 8 through 15 use scalar width analysis and JDK 16
and later automatically select the Vector API implementation when
`jdk.incubator.vector` is resolved.
[...]
| `compressString` | Enables or disables string compression
for smaller size.
[...]
| `classLoader` | The classloader is fixed per `Fory`
instance because Fory caches class metadata. To use a different loader, create
a new `Fory` or `ThreadSafeFory` configured with that loader, or rely on the
thread context classloader before first class resolution.
[...]
| `compatible` | Schema evolution mode. `true`: readers
can tolerate compatible field additions, removals, and reordering. `false`: use
only when every reader and writer always uses the same class schema and you
want faster serialization and smaller size. When unset, compatible mode is
enabled in both xlang and native mode. [See more](schema-evolution.md).
[...]
diff --git a/docs/guide/java/graalvm-support.md
b/docs/guide/java/graalvm-support.md
index 1f2503fe1e..72c8467bc0 100644
--- a/docs/guide/java/graalvm-support.md
+++ b/docs/guide/java/graalvm-support.md
@@ -21,66 +21,54 @@ license: |
## GraalVM Native Image
-GraalVM `native image` compiles Java code into native executables
ahead-of-time, resulting in faster startup and lower memory usage. However,
native images don't support runtime JIT compilation or reflection without
explicit configuration.
+GraalVM Native Image compiles Java applications ahead of time. Because a
native image cannot
+discover every reflective access or generate serializers at runtime, Fory
prepares serializers and
+the required metadata while the image is built.
-Apache Foryβ’ works excellently with GraalVM native image by using **codegen
instead of reflection**. All serializer code is generated at build time,
eliminating the need for reflection configuration files in most cases.
+`fory-core` contains Fory's GraalVM Feature and activates it automatically.
Applications do not need
+an additional Fory artifact or a `--features` option.
## How It Works
-Fory generates serialization code at GraalVM build time when you:
+Prepare each Fory instance during build-time class initialization:
-1. Create Fory as a **static** field
-2. **Register** all classes in a static initializer
-3. Call `fory.ensureSerializersCompiled()` to compile serializers
-4. Configure the class to initialize at build time via
`native-image.properties`
+1. Store the Fory instance in a static field.
+2. Register every application class that the native executable will serialize.
+3. Call `fory.ensureSerializersCompiled()` after registration is complete.
+4. Configure the owning class for build-time initialization.
-**The main benefit**: You don't need to configure [reflection
json](https://www.graalvm.org/latest/reference-manual/native-image/metadata/#specifying-reflection-metadata-in-json)
or [serialization
json](https://www.graalvm.org/latest/reference-manual/native-image/metadata/#serialization)
for most serializable classes.
+The Feature uses those registrations to provide the Native Image metadata
required by Fory,
+including metadata for private constructors, records, serializer constructors,
and registered proxy
+shapes. Application classes still need to be registered with Fory before
serializers are compiled.
-Note: Fory's `asyncCompilationEnabled` option is automatically disabled for
GraalVM native image since runtime JIT is not supported.
+Fory disables asynchronous serializer compilation in a native image because
runtime just-in-time
+compilation is unavailable.
## Basic Usage
-### Step 0: Add the GraalVM Support Dependency
-
-Add `fory-graalvm-feature` to your application dependencies when building a
native image:
-
-```xml
-<dependency>
- <groupId>org.apache.fory</groupId>
- <artifactId>fory-graalvm-feature</artifactId>
- <version>${fory.version}</version>
-</dependency>
-```
-
-This dependency already ships GraalVM feature metadata in
`META-INF/native-image`, so adding it
-automatically enables `org.apache.fory.graalvm.feature.ForyGraalVMFeature`
during native-image
-builds.
-
-### Step 1: Create Fory and Register Classes
+### Create Fory and Register Classes
```java
import org.apache.fory.Fory;
public class Example {
- // Must be static field
- static Fory fory;
+ private static final Fory FORY;
static {
- fory = Fory.builder().withXlang(false).build();
- fory.register(MyClass.class);
- fory.register(AnotherClass.class);
- // Compile all serializers at build time
- fory.ensureSerializersCompiled();
+ FORY = Fory.builder().withXlang(false).build();
+ FORY.register(MyClass.class);
+ FORY.register(AnotherClass.class);
+ FORY.ensureSerializersCompiled();
}
public static void main(String[] args) {
- byte[] bytes = fory.serialize(new MyClass());
- MyClass obj = (MyClass) fory.deserialize(bytes);
+ byte[] bytes = FORY.serialize(new MyClass());
+ MyClass obj = (MyClass) FORY.deserialize(bytes);
}
}
```
-### Step 2: Configure Build-Time Initialization
+### Configure Build-Time Initialization
Create
`resources/META-INF/native-image/your-group/your-artifact/native-image.properties`:
@@ -88,43 +76,37 @@ Create
`resources/META-INF/native-image/your-group/your-artifact/native-image.pr
Args = --initialize-at-build-time=com.example.Example
```
-## What `fory-graalvm-feature` Handles
+## Registered Classes
-After you add the `fory-graalvm-feature` dependency, Fory automatically
registers the extra
-GraalVM metadata needed by advanced cases such as:
+During the native-image build, Fory automatically registers the metadata
needed for registered
+classes, including:
-- **Private constructors** (classes without accessible no-arg constructor)
-- **Private inner classes/records**
-- **Dynamic proxy serialization**
+- Classes with private constructors
+- Private nested classes and records
+- Serializer constructors
+- Dynamic proxy shapes registered through `GraalvmSupport`
-This removes the need for manual `reflect-config.json` in most applications.
Your own
-`native-image.properties` still only needs to configure your build-time
initialized bootstrap
+For Fory, your application metadata only needs to configure its build-time
initialized bootstrap
class, for example:
```properties
Args = --initialize-at-build-time=com.example.Example
```
-| Scenario | Without Feature | With Feature
|
-| ------------------------------- | ------------------------- |
--------------- |
-| Public classes with no-arg ctor | Works | Works
|
-| Private constructors | Needs reflect-config.json |
Auto-registered |
-| Private inner records | Needs reflect-config.json |
Auto-registered |
-| Dynamic proxies | Needs manual config |
Auto-registered |
-
### Example with Private Record
```java
+import org.apache.fory.Fory;
+
public class Example {
- // Private inner record - requires ForyGraalVMFeature
private record PrivateRecord(int id, String name) {}
- static Fory fory;
+ private static final Fory FORY;
static {
- fory = Fory.builder().withXlang(false).build();
- fory.register(PrivateRecord.class);
- fory.ensureSerializersCompiled();
+ FORY = Fory.builder().withXlang(false).build();
+ FORY.register(PrivateRecord.class);
+ FORY.ensureSerializersCompiled();
}
}
```
@@ -132,6 +114,7 @@ public class Example {
### Example with Dynamic Proxy
```java
+import org.apache.fory.Fory;
import org.apache.fory.platform.GraalvmSupport;
public class ProxyExample {
@@ -143,27 +126,26 @@ public class ProxyExample {
String traceId();
}
- static Fory fory;
+ private static final Fory FORY;
static {
- fory = Fory.builder().withXlang(false).build();
- // Register the exact interface list used by Proxy.newProxyInstance(...)
+ FORY = Fory.builder().withXlang(false).build();
GraalvmSupport.registerProxySupport(MyService.class, Audited.class);
- fory.ensureSerializersCompiled();
+ FORY.ensureSerializersCompiled();
}
}
```
Use `registerProxySupport(MyService.class)` for a single-interface proxy. For
proxies that implement
-multiple interfaces, pass the full interface list in the same order used to
create the proxy. With
-`fory-graalvm-feature` on the classpath, this replaces manual
`proxy-config.json` entries for those
-registered proxy shapes.
+multiple interfaces, pass the full interface list in the same order used to
create the proxy. Call
+this method before `ensureSerializersCompiled()`.
## Thread-Safe Fory
For multi-threaded applications, use `ThreadLocalFory`:
```java
+import java.util.List;
import org.apache.fory.Fory;
import org.apache.fory.ThreadLocalFory;
import org.apache.fory.ThreadSafeFory;
@@ -171,21 +153,23 @@ import org.apache.fory.ThreadSafeFory;
public class ThreadSafeExample {
public record Foo(int f1, String f2, List<String> f3) {}
- static ThreadSafeFory fory;
+ private static final ThreadSafeFory FORY;
static {
- fory = new ThreadLocalFory(builder -> {
- Fory f = builder.build();
- f.register(Foo.class);
- f.ensureSerializersCompiled();
- return f;
- });
+ FORY =
+ new ThreadLocalFory(
+ builder -> {
+ Fory f = builder.build();
+ f.register(Foo.class);
+ f.ensureSerializersCompiled();
+ return f;
+ });
}
public static void main(String[] args) {
Foo foo = new Foo(10, "abc", List.of("str1", "str2"));
- byte[] bytes = fory.serialize(foo);
- Foo result = (Foo) fory.deserialize(bytes);
+ byte[] bytes = FORY.serialize(foo);
+ Foo result = (Foo) FORY.deserialize(bytes);
}
}
```
@@ -200,26 +184,23 @@ If you see this error:
Type com.example.MyClass is instantiated reflectively but was never registered
```
-**Solution**: Register the class with Fory (don't add to reflect-config.json):
+Register the class before compiling serializers:
```java
fory.register(MyClass.class);
fory.ensureSerializersCompiled();
```
-If the class has a private constructor, either:
-
-1. Make sure `fory-graalvm-feature` is already on the native-image classpath,
or
-2. Create a `reflect-config.json` for that specific class
+If registration is conditional, make sure the same branch runs during
build-time initialization.
## Framework Integration
For framework developers integrating Fory:
-1. Provide a configuration file for users to list serializable classes
-2. Load those classes and call `fory.register(Class<?>)` for each
-3. Call `fory.ensureSerializersCompiled()` after all registrations
-4. Configure your integration class for build-time initialization
+1. Provide a configuration file for users to list serializable classes.
+2. Load those classes and call `fory.register(Class<?>)` for each.
+3. Call `fory.ensureSerializersCompiled()` after all registrations.
+4. Configure your integration class for build-time initialization.
## Benchmark
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]