blob: d73739cd96206f6742ae6f22941a3084fd6e2cbd [file] [view]
---
title: GraalVM Native Image
sidebar_position: 15
id: graalvm
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
## 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:
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 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
```java
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`:
```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:
```properties
Args = --initialize-at-build-time=com.example.Example
```
### Example with Private Record
```java
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
```java
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`:
```java
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:
```java
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:
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.