跳到主要内容
版本:dev

GraalVM Native Image

Reachable Models

Fory JSON has its own Native Image Feature and does not use the Fory annotation processor. Add @JsonType to each reachable concrete object model that the native executable reads or writes:

import org.apache.fory.json.ForyJson;
import org.apache.fory.json.annotation.JsonType;
import org.apache.fory.json.annotation.JsonValidator;

@JsonType
public final class User {
public long id;
public String name;

@JsonValidator
public void validate() {
if (id < 0) {
throw new IllegalArgumentException("id must not be negative");
}
}
}

public class JsonExample {
public static void main(String[] args) {
ForyJson json = ForyJson.builder().build();
User user = json.fromJson("{\"id\":1,\"name\":\"Ada\"}", User.class);
System.out.println(json.toJson(user));
}
}

This is sufficient for correct native execution. During image construction, Fory JSON retains the model metadata and prepares its field, property, creator, record, and JsonAnySetter access. At runtime, ForyJson.builder().build() can therefore use interpreted codecs without application reflection configuration, package exports or opens, or build-time initialization.

Generated Codecs

To include generated codecs for a configuration, return that completed configuration from a reachable @ForyJsonProvider:

import org.apache.fory.json.ForyJson;
import org.apache.fory.json.PropertyNamingStrategy;
import org.apache.fory.json.annotation.ForyJsonProvider;

@ForyJsonProvider
public final class JsonConfigs {
private final ForyJson api =
ForyJson.builder()
.writeNullFields(true)
.withPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.registerCodec(Money.class, new MoneyCodec())
.build();

public JsonConfigs() {}

public ForyJson api() {
return api;
}
}

The provider class must be public and concrete and have a public no-argument constructor. Provider members are public, non-static, zero-argument instance methods whose exact return type is ForyJson. Inherited superclass methods and public interface default methods are included. A provider may return multiple configurations, and multiple providers may be reachable. Equivalent configurations are generated once.

Provider objects exist only while the image is built. Prefer a dedicated configuration class with instance fields and methods as shown above; no application native-image.properties entry is needed, and the provider package does not need to be exported or opened to Fory. Static provider methods and fields are not supported.

Only configurations returned by a provider receive generated codecs. The default configuration is not generated implicitly. If a codegen-enabled runtime configuration was not included, Fory JSON uses its prepared interpreted codecs and logs one process-wide warning recommending a reachable @ForyJsonProvider. withCodegen(false) explicitly selects interpreted codecs and does not request generated-codec lookup. Asynchronous compilation is disabled in a native executable.

Mixins

Use Fory JSON Mixins for models that cannot be modified:

import org.apache.fory.json.ForyJson;
import org.apache.fory.json.annotation.JsonMixin;
import org.apache.fory.json.annotation.JsonProperty;

@JsonMixin(target = ThirdPartyUser.class)
public abstract class ThirdPartyUserMixin {
@JsonProperty("user_id")
long id;
}

public class JsonExample {
public static void main(String[] args) {
ForyJson json =
ForyJson.builder().registerMixin(ThirdPartyUserMixin.class).build();
ThirdPartyUser user = json.fromJson("{\"user_id\":1}", ThirdPartyUser.class);
System.out.println(json.toJson(user));
}
}

JsonMixin is a build-time entry point for its exact declared target, so the target does not need JsonType solely to use the Mixin. The registered Mixin class literal must be reachable from the application. The Native Image Feature retains the target metadata and prepares the same access as it does for a direct JsonType model. A provider configuration generates the Mixin target only when that exact Mixin is registered in the returned ForyJson.

Only one source is enabled for an exact target in a built ForyJson. Later registration replaces an earlier source for subsequent build() calls; a runtime keeps the immutable snapshot it was built with.

Type Discovery and Construction

The fory-json artifact activates its Native Image Feature automatically. @JsonType is not inherited, so annotate every concrete runtime model. An annotated base with a class-literal @JsonSubTypes table registers its listed subtypes automatically. Dedicated supported containers, including EnumMap and EnumSet, use their built-in factories. Other reachable concrete Collection and Map root types require a public no-argument constructor. A class referenced only by a runtime string is not reachable; JsonSubTypes.Type.className is therefore unsupported in a native image.

Do not add application reflection configuration as a replacement for the generated configuration. The native executable resolves the same effective annotations as the JVM.

Annotations and Custom Codecs

Effective JsonValidator methods must be public instance methods with no arguments and a void return type. A model with a directly declared validator must use JsonType. A validator contributed by a registered Mixin uses that exact Mixin-target pair, so the target does not also need JsonType. The Native Image Feature prepares validator access for interpreted configurations and provider-generated codecs invoke the same effective validators. Do not add reflection configuration for validators. Complete custom codecs, complete JsonValue representations, and creators that enforce validation themselves perform their own validation.

Type, field, effective ordinary getter, setter value parameter, and JsonCreator parameter @JsonCodec annotations are supported. The Feature retains every selected complete-value, element, content, Map-key, and Map-value codec constructor. This is the same annotation model used on the JVM and Android.

JsonValue fields and effective public zero-argument methods are supported, including matching one-String JsonCreator constructors and public static factories. Fixed JsonRawValue fields and getters support trusted raw String values, and fixed JsonBase64 fields and getters support Base64 byte[] values as on the JVM. JsonFormat date/time fields use the same direct-field, one-wrapper-level, and timezone behavior as on the JVM. For direct target annotations, annotate each reachable owning model with JsonType so Native Image retains these members and the Base64 codec constructor. A directly annotated JsonValue Record uses its generated component accessor and canonical constructor operations. An effective declaration supplied by a Mixin uses the Mixin workflow above instead.

JsonAnyProperty and JsonAnyGetter flatten their Map into the enclosing object. Use @JsonCodec(valueCodec = ...) on that field or getter to customize each dynamic value. A second JsonAnySetter parameter may use the normal configuration for its own value shape.

JsonUnwrapped uses the same behavior as on the JVM. For direct target annotations, annotate the containing model and every unwrapped child or intermediate object with JsonType. A Mixin retains the unwrapped models reached by its effective schema; register a separate exact Mixin for a child only when that child's annotations also need an overlay.

Child codecs act on one direct level. elementCodec supports Collection, Java arrays, and AtomicReferenceArray; contentCodec supports Optional and AtomicReference; keyCodec and valueCodec support Map keys and values. A complete value codec cannot be combined with a child codec.

An annotation codec must have a public no-argument constructor. Fory prepares that constructor during Native Image construction, so application modules do not need to export or open the codec package. A codec instance supplied through registerCodec is constructed by the application and needs no annotation-constructor metadata.