GraalVM Native Image
GraalVM Native Image
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.
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
Prepare each Fory instance during build-time class initialization:
- Store the Fory instance in a static field.
- Register every application class that the native executable will serialize.
- Call
fory.ensureSerializersCompiled()after registration is complete. - Configure the owning class for build-time initialization.
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.
Fory disables asynchronous serializer compilation in a native image because runtime just-in-time compilation is unavailable.
Basic Usage
Create Fory and Register Classes
import org.apache.fory.Fory;
public class Example {
private static final Fory FORY;
static {
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);
}
}
Configure Build-Time Initialization
Create resources/META-INF/native-image/your-group/your-artifact/native-image.properties:
Args = --initialize-at-build-time=com.example.Example
Registered Classes
During the native-image build, Fory automatically registers the metadata needed for registered classes, including:
- Classes with private constructors
- Private nested classes and records
- Serializer constructors
- Dynamic proxy shapes registered through
GraalvmSupport
For Fory, your application metadata only needs to configure its build-time initialized bootstrap class, for example:
Args = --initialize-at-build-time=com.example.Example
Example with Private Record
import org.apache.fory.Fory;
public class Example {
private record PrivateRecord(int id, String name) {}
private static final Fory FORY;
static {
FORY = Fory.builder().withXlang(false).build();
FORY.register(PrivateRecord.class);
FORY.ensureSerializersCompiled();
}
}
Example with Dynamic Proxy
import org.apache.fory.Fory;
import org.apache.fory.platform.GraalvmSupport;
public class ProxyExample {
public interface MyService {
String execute();
}
public interface Audited {
String traceId();
}
private static final Fory FORY;
static {
FORY = Fory.builder().withXlang(false).build();
GraalvmSupport.registerProxySupport(MyService.class, Audited.class);
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. Call
this method before ensureSerializersCompiled().
Thread-Safe Fory
For multi-threaded applications, use ThreadLocalFory:
import java.util.List;
import org.apache.fory.Fory;
import org.apache.fory.ThreadLocalFory;
import org.apache.fory.ThreadSafeFory;
public class ThreadSafeExample {
public record Foo(int f1, String f2, List<String> f3) {}
private static final ThreadSafeFory FORY;
static {
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);
}
}
Troubleshooting
"Type is instantiated reflectively but was never registered"
If you see this error:
Type com.example.MyClass is instantiated reflectively but was never registered
Register the class before compiling serializers:
fory.register(MyClass.class);
fory.ensureSerializersCompiled();
If registration is conditional, make sure the same branch runs during build-time initialization.
Framework Integration
For framework developers integrating Fory:
- Provide a configuration file for users to list serializable classes.
- Load those classes and call
fory.register(Class<?>)for each. - Call
fory.ensureSerializersCompiled()after all registrations. - Configure your integration class for build-time initialization.