| --- |
| title: Static Generated Serializers |
| sidebar_position: 8 |
| id: static_generated_serializers |
| 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. |
| --- |
| |
| Static generated serializers are Java serializers generated by javac during your application build. |
| They are useful when runtime code generation is disabled or unavailable. |
| |
| Use them when: |
| |
| - you run on Android. |
| - you run an ordinary JVM with `ForyBuilder#withCodegen(false)` and want generated serializers. |
| - your Android model classes use Fory type-use annotations such as `@Ref`, `@UInt8Type`, or |
| `@Float16Type`. |
| |
| For GraalVM native images, follow [GraalVM Support](graalvm-support.md) instead. |
| |
| ## Install The Annotation Processor |
| |
| Add `fory-annotation-processor` to the annotation processor path of the module that compiles your |
| serializable classes: |
| |
| ```xml |
| <build> |
| <plugins> |
| <plugin> |
| <groupId>org.apache.maven.plugins</groupId> |
| <artifactId>maven-compiler-plugin</artifactId> |
| <configuration> |
| <annotationProcessorPaths> |
| <path> |
| <groupId>org.apache.fory</groupId> |
| <artifactId>fory-annotation-processor</artifactId> |
| <version>${fory.version}</version> |
| </path> |
| </annotationProcessorPaths> |
| </configuration> |
| </plugin> |
| </plugins> |
| </build> |
| ``` |
| |
| The generated serializers depend on `fory-core` at runtime. Applications opt in by adding the |
| annotation processor; `fory-core` does not depend on it. |
| |
| ## Annotate Classes |
| |
| Annotate each serializable class with `@ForyStruct`: |
| |
| ```java |
| import org.apache.fory.annotation.ForyStruct; |
| |
| @ForyStruct |
| public class Order { |
| public long id; |
| public String note; |
| |
| public Order() {} |
| } |
| ``` |
| |
| The processor generates serializer classes in the same Java package as the annotated class. For |
| `Order`, the generated classes are: |
| |
| - `Order_ForySerializer` for xlang mode. |
| - `Order_ForyNativeSerializer` for Java native mode. |
| |
| For a static nested type such as `Outer.Inner`, the generated top-level classes are |
| `Outer_Inner_ForySerializer` and `Outer_Inner_ForyNativeSerializer`. |
| |
| ## Field Debug Tracing |
| |
| Add `@ForyDebug` next to `@ForyStruct` when you need generated serializers to include field-level |
| debug tracing hooks. The generated code prints those traces only when |
| `ENABLE_FORY_DEBUG_OUTPUT=1`. |
| |
| ```java |
| import org.apache.fory.annotation.ForyDebug; |
| import org.apache.fory.annotation.ForyStruct; |
| |
| @ForyStruct |
| @ForyDebug |
| public class DebugOrder { |
| public long id; |
| public String note; |
| |
| public DebugOrder() {} |
| } |
| ``` |
| |
| ## Runtime Use |
| |
| Fory uses static generated serializers when they are available on: |
| |
| - Android. |
| - ordinary JVMs with `ForyBuilder#withCodegen(false)`. |
| - compatible-mode reads when the target struct has a generated serializer. |
| |
| On an ordinary JVM with `codegen=true`, Fory continues to prefer runtime-generated serializers. |
| |
| Fory resolves generated serializers from the registered target class name. Application code |
| should not reference generated serializer classes directly. |
| |
| ## Field Access Rules |
| |
| Generated serializers must be able to access serialized fields or their accessors at compile time. |
| |
| - Public, protected, and package-private fields can be accessed directly when Java package access |
| allows same-package generated serializers to use them. |
| - Private serialized fields must have accessible non-private getter and setter methods, or be |
| excluded with `transient` or Fory `@Ignore`. |
| - Public, protected, and package-private getter/setter methods are accepted when they are accessible |
| from the generated serializer package. |
| - Final fields are not supported for normal mutable classes because generated read and copy methods |
| must assign fields. Use records for constructor-based immutable values. |
| |
| For records, generated serializers use public record accessors and construct values through the |
| canonical record constructor. Ignored record components are skipped by serialization and copy, and |
| their constructor arguments use Java default values during generated read/copy. |
| |
| ## Type-Use Annotations On Android |
| |
| On Android, static generated serializers are required when a class uses Fory type-use annotations on |
| nested types: |
| |
| ```java |
| import java.util.List; |
| import org.apache.fory.annotation.ForyStruct; |
| import org.apache.fory.annotation.UInt8Type; |
| |
| @ForyStruct |
| public class ImageBlock { |
| public List<@UInt8Type Integer> pixels; |
| } |
| ``` |
| |
| Without the generated serializer metadata, Android may not expose enough nested type information for |
| Fory to preserve annotations such as `@Ref`, `@Int8Type`, `@UInt8Type`, `@Float16Type`, or |
| `@BFloat16Type`. |
| |
| The annotation processor emits generated consumer R8/ProGuard rules under `META-INF/proguard/` for |
| the exact serializer constructors used by Fory. Android applications should not add broad generated |
| serializer keep rules by hand. |
| |
| ## Compatible Reads |
| |
| Static generated serializers support both normal serialization and compatible-mode reads. Compatible |
| reads match remote fields to local fields, skip fields that no longer exist locally, and keep Java |
| default values for fields that are missing from the remote payload. |