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 c484a5a6d π synced local 'docs/docs/guide/' with remote 'docs/guide/'
c484a5a6d is described below
commit c484a5a6dd655466d07e62905947a6282b0155ea
Author: chaokunyang <[email protected]>
AuthorDate: Thu Dec 4 07:43:11 2025 +0000
π synced local 'docs/docs/guide/' with remote 'docs/guide/'
---
docs/docs/guide/graalvm_guide.md | 228 ++++++++++++++++++++++-----------------
1 file changed, 128 insertions(+), 100 deletions(-)
diff --git a/docs/docs/guide/graalvm_guide.md b/docs/docs/guide/graalvm_guide.md
index 3f85c2c70..2a1f6468f 100644
--- a/docs/docs/guide/graalvm_guide.md
+++ b/docs/docs/guide/graalvm_guide.md
@@ -21,179 +21,207 @@ license: |
## GraalVM Native Image
-GraalVM `native image` can compile java code into native code ahead to build
faster, smaller, leaner applications.
-The native image doesn't have a JIT compiler to compile bytecode into machine
code, and doesn't support
-reflection unless configure reflection file.
+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.
-Apache Foryβ’ runs on GraalVM native image pretty well. Apache Foryβ’ generates
all serializer code for `Fory JIT framework` and
`MethodHandle/LambdaMetafactory` at graalvm build time. Then use those
generated code for serialization at runtime without
-any extra cost, the performance is great.
+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.
-In order to use Apache Foryβ’ on graalvm native image, you must create Fory as
an **static** field of a class, and **register** all classes at
-the enclosing class initialize time. Then configure `native-image.properties`
under
-`resources/META-INF/native-image/$xxx/native-image.properties` to tell graalvm
to init the class at native image
-build time. For example, here we configure `org.apache.fory.graalvm.Example`
class be init at build time:
+## How It Works
-```properties
-Args = --initialize-at-build-time=org.apache.fory.graalvm.Example
-```
+Fory generates serialization code at GraalVM build time when you:
-**The main benefit of using Fory with GraalVM is that 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 your serializable classes!** This eliminates the tedious, cumbersome and
error-prone configuration process.
+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`
-Fory achieves this by using **codegen instead of reflection** - all
serialization code is generated at build time when you call:
+**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.
-- `fory.register(YourClass.class)` to register your classes
-- `fory.ensureSerializersCompiled()` to compile serializers at build time
+Note: Fory's `asyncCompilationEnabled` option is automatically disabled for
GraalVM native image since runtime JIT is not supported.
-Note that Fory `asyncCompilationEnabled` option will be disabled automatically
for graalvm native image since graalvm
-native image doesn't support JIT at the image run time.
+## Basic Usage
-## Registering Your Classes
+### Step 1: Create Fory and Register Classes
-If you encounter a GraalVM error like:
+```java
+import org.apache.fory.Fory;
-```
-Type com.example.MyClass is instantiated reflectively but was never registered
-```
+public class Example {
+ // Must be static field
+ static Fory fory;
-This means you need to register your class with Fory. **Do NOT add it to
reflect-config.json** - instead, register it with Fory's codegen system:
+ static {
+ fory = Fory.builder().build();
+ fory.register(MyClass.class);
+ fory.register(AnotherClass.class);
+ // Compile all serializers at build time
+ fory.ensureSerializersCompiled();
+ }
-```java
-static {
- fory = Fory.builder().build();
- // register class
- fory.register(MyClass.class);
- // ensure all serializers for registered classes being compiled by fory at
graalvm native image build time.
- fory.ensureSerializersCompiled();
+ public static void main(String[] args) {
+ byte[] bytes = fory.serialize(new MyClass());
+ MyClass obj = (MyClass) fory.deserialize(bytes);
+ }
}
```
-And make sure the class executing static registering is initialized at build
time in `native-image.properties`:
+### Step 2: Configure Build-Time Initialization
+
+Create
`resources/META-INF/native-image/your-group/your-artifact/native-image.properties`:
```properties
-Args = --initialize-at-build-time=com.example.MyForySerializer
+Args = --initialize-at-build-time=com.example.Example
```
-This approach is much more efficient than reflection-based serialization and
eliminates the need for complex GraalVM configuration files.
+## ForyGraalVMFeature (Optional)
-## Not thread-safe Fory
+For most types with public constructors, the basic setup above is sufficient.
However, some advanced cases require reflection registration:
-Example:
+- **Private constructors** (classes without accessible no-arg constructor)
+- **Private inner classes/records**
+- **Dynamic proxy serialization**
-```java
-import org.apache.fory.Fory;
-import org.apache.fory.util.Preconditions;
+The `fory-graalvm-feature` module automatically handles these cases,
eliminating the need for manual `reflect-config.json` configuration.
+
+### Adding the Dependency
-import java.util.List;
-import java.util.Map;
+```xml
+<dependency>
+ <groupId>org.apache.fory</groupId>
+ <artifactId>fory-graalvm-feature</artifactId>
+ <version>${fory.version}</version>
+</dependency>
+```
+
+### Enabling the Feature
+Add to your `native-image.properties`:
+
+```properties
+Args = --initialize-at-build-time=com.example.Example \
+ --features=org.apache.fory.graalvm.feature.ForyGraalVMFeature
+```
+
+### What ForyGraalVMFeature Handles
+
+| 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
public class Example {
- public record Record (
- int f1,
- String f2,
- List<String> f3,
- Map<String, Long> f4) {
- }
+ // Private inner record - requires ForyGraalVMFeature
+ private record PrivateRecord(int id, String name) {}
static Fory fory;
static {
fory = Fory.builder().build();
- // register class
- fory.register(Record.class);
- // ensure all serializers for registered classes being compiled by fory at
graalvm native image build time.
+ fory.register(PrivateRecord.class);
fory.ensureSerializersCompiled();
}
-
- public static void main(String[] args) {
- Record record = new Record(10, "abc", List.of("str1", "str2"),
Map.of("k1", 10L, "k2", 20L));
- System.out.println(record);
- byte[] bytes = fory.serialize(record);
- Object o = fory.deserialize(bytes);
- System.out.println(o);
- Preconditions.checkArgument(record.equals(o));
- }
}
```
-Then add `org.apache.fory.graalvm.Example` build time init to
`native-image.properties` configuration:
+### Example with Dynamic Proxy
-```properties
-Args = --initialize-at-build-time=org.apache.fory.graalvm.Example
+```java
+import org.apache.fory.util.GraalvmSupport;
+
+public class ProxyExample {
+ public interface MyService {
+ String execute();
+ }
+
+ static Fory fory;
+
+ static {
+ fory = Fory.builder().build();
+ // Register proxy interface for serialization
+ GraalvmSupport.registerProxySupport(MyService.class);
+ fory.ensureSerializersCompiled();
+ }
+}
```
-## Thread-safe Fory
+## Thread-Safe Fory
+
+For multi-threaded applications, use `ThreadLocalFory`:
```java
import org.apache.fory.Fory;
import org.apache.fory.ThreadLocalFory;
import org.apache.fory.ThreadSafeFory;
-import org.apache.fory.util.Preconditions;
-
-import java.util.List;
-import java.util.Map;
public class ThreadSafeExample {
- public record Foo (
- int f1,
- String f2,
- List<String> f3,
- Map<String, Long> f4) {
- }
+ public record Foo(int f1, String f2, List<String> f3) {}
static ThreadSafeFory fory;
static {
fory = new ThreadLocalFory(classLoader -> {
Fory f = Fory.builder().build();
- // register class
f.register(Foo.class);
- // ensure all serializers for registered classes being compiled by fory
at graalvm native image build time.
- fory.ensureSerializersCompiled();
+ f.ensureSerializersCompiled();
return f;
});
}
public static void main(String[] args) {
- System.out.println(fory.deserialize(fory.serialize("abc")));
- System.out.println(fory.deserialize(fory.serialize(List.of(1,2,3))));
- System.out.println(fory.deserialize(fory.serialize(Map.of("k1", 1, "k2",
2))));
- Foo foo = new Foo(10, "abc", List.of("str1", "str2"), Map.of("k1", 10L,
"k2", 20L));
- System.out.println(foo);
+ Foo foo = new Foo(10, "abc", List.of("str1", "str2"));
byte[] bytes = fory.serialize(foo);
- Object o = fory.deserialize(bytes);
- System.out.println(o);
+ Foo result = (Foo) fory.deserialize(bytes);
}
}
```
-Then add `org.apache.fory.graalvm.ThreadSafeExample` build time init to
`native-image.properties` configuration:
+## Troubleshooting
-```properties
-Args = --initialize-at-build-time=org.apache.fory.graalvm.ThreadSafeExample
+### "Type is instantiated reflectively but was never registered"
+
+If you see this error:
+
+```
+Type com.example.MyClass is instantiated reflectively but was never registered
```
-## Framework Integration
+**Solution**: Register the class with Fory (don't add to reflect-config.json):
-For framework developers, if you want to integrate fory for serialization, you
can provided a configuration file to let
-the users to list all the classes they want to serialize, then you can load
those classes and invoke
-`org.apache.fory.Fory.register(Class<?>)` to register those classes in your
Fory integration class. After all classes are registered, you need to invoke
`org.apache.fory.Fory.ensureSerializersCompiled()` to compile serializers at
build time, and configure that class be initialized at graalvm native image
build time.
+```java
+fory.register(MyClass.class);
+fory.ensureSerializersCompiled();
+```
-## Benchmark
+If the class has a private constructor, either:
-Here we give two class benchmarks between Fory and Graalvm Serialization.
+1. Add `fory-graalvm-feature` dependency, or
+2. Create a `reflect-config.json` for that specific class
-When Fory compression is disabled:
+## Framework Integration
-- Struct: Fory is `46x speed, 43% size` compared to JDK.
-- Pojo: Fory is `12x speed, 56% size` compared to JDK.
+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
+
+## Benchmark
-When Fory compression is enabled:
+Performance comparison between Fory and GraalVM JDK Serialization:
-- Struct: Fory is `24x speed, 31% size` compared to JDK.
-- Pojo: Fory is `12x speed, 48% size` compared to JDK.
+| Type | Compression | Speed | Size |
+| ------ | ----------- | ---------- | ---- |
+| Struct | Off | 46x faster | 43% |
+| Struct | On | 24x faster | 31% |
+| Pojo | Off | 12x faster | 56% |
+| Pojo | On | 12x faster | 48% |
-See
[[Benchmark.java](https://github.com/apache/fory/blob/main/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java)]
for benchmark code.
+See
[Benchmark.java](https://github.com/apache/fory/blob/main/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java)
for benchmark code.
### Struct Benchmark
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]