You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by ch...@apache.org on 2026/02/08 02:38:07 UTC

(fory-site) branch main updated (5e87a88c4a -> 4f85c20d2e)

This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git


    from 5e87a88c4a 🔄 synced local 'docs/benchmarks/' with remote 'docs/benchmarks/'
     new fcb79281ce 🔄 synced local 'docs/guide/' with remote 'docs/guide/'
     new 4f85c20d2e 🔄 synced local 'docs/compiler/' with remote 'docs/compiler/'

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 docs/compiler/generated-code.md      | 729 +++++++++++++++++++----------------
 docs/compiler/schema-idl.md          |  77 ++--
 docs/guide/go/codegen.md             |  22 +-
 docs/guide/java/compression.md       |   4 +-
 docs/guide/java/configuration.md     |  12 +-
 docs/guide/java/schema-evolution.md  |   2 +-
 docs/guide/python/configuration.md   |  32 +-
 docs/guide/python/index.md           |   2 +-
 docs/guide/rust/schema-evolution.md  |   2 +-
 docs/guide/rust/type-registration.md |  10 +-
 10 files changed, 474 insertions(+), 418 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org


(fory-site) 01/02: 🔄 synced local 'docs/guide/' with remote 'docs/guide/'

Posted by ch...@apache.org.
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

commit fcb79281cea8bb73edd081bb6be47e8c0c6fc660
Author: chaokunyang <sh...@gmail.com>
AuthorDate: Sun Feb 8 02:38:03 2026 +0000

    🔄 synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/go/codegen.md             | 22 ++++++++++++++++------
 docs/guide/java/compression.md       |  4 ++--
 docs/guide/java/configuration.md     | 12 ++++++------
 docs/guide/java/schema-evolution.md  |  2 +-
 docs/guide/python/configuration.md   | 32 +++++++++++++++++---------------
 docs/guide/python/index.md           |  2 +-
 docs/guide/rust/schema-evolution.md  |  2 +-
 docs/guide/rust/type-registration.md | 10 +++++-----
 8 files changed, 49 insertions(+), 37 deletions(-)

diff --git a/docs/guide/go/codegen.md b/docs/guide/go/codegen.md
index 18850d7174..19cb384580 100644
--- a/docs/guide/go/codegen.md
+++ b/docs/guide/go/codegen.md
@@ -130,15 +130,25 @@ Strongly-typed serialization methods:
 ```go
 type User_ForyGenSerializer struct{}
 
-func (User_ForyGenSerializer) WriteTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
+func NewSerializerFor_User() fory.Serializer {
+    return &User_ForyGenSerializer{}
+}
+
+func (User_ForyGenSerializer) WriteTyped(ctx *fory.WriteContext, v *User) error {
+    buf := ctx.Buffer()
     buf.WriteInt64(v.ID)
-    fory.WriteString(buf, v.Name)
+    ctx.WriteString(v.Name)
     return nil
 }
 
-func (User_ForyGenSerializer) ReadTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
-    v.ID = buf.ReadInt64()
-    v.Name = fory.ReadString(buf)
+func (User_ForyGenSerializer) ReadTyped(ctx *fory.ReadContext, v *User) error {
+    err := ctx.Err()
+    buf := ctx.Buffer()
+    v.ID = buf.ReadInt64(err)
+    v.Name = ctx.ReadString()
+    if ctx.HasError() {
+        return ctx.TakeError()
+    }
     return nil
 }
 ```
@@ -149,7 +159,7 @@ Serializers are registered in `init()`:
 
 ```go
 func init() {
-    fory.RegisterGenSerializer(User{}, User_ForyGenSerializer{})
+    fory.RegisterSerializerFactory((*User)(nil), NewSerializerFor_User)
 }
 ```
 
diff --git a/docs/guide/java/compression.md b/docs/guide/java/compression.md
index f79676a5bf..11cabe634c 100644
--- a/docs/guide/java/compression.md
+++ b/docs/guide/java/compression.md
@@ -98,8 +98,8 @@ String compression can be enabled via `ForyBuilder#withStringCompressed(true)`.
 | ------------------- | --------------------------------------------- | ------- |
 | `compressInt`       | Enable int compression                        | `true`  |
 | `compressLong`      | Enable long compression                       | `true`  |
-| `compressIntArray`  | Enable SIMD int array compression (Java 16+)  | `true`  |
-| `compressLongArray` | Enable SIMD long array compression (Java 16+) | `true`  |
+| `compressIntArray`  | Enable SIMD int array compression (Java 16+)  | `false` |
+| `compressLongArray` | Enable SIMD long array compression (Java 16+) | `false` |
 | `compressString`    | Enable string compression                     | `false` |
 
 ## Performance Considerations
diff --git a/docs/guide/java/configuration.md b/docs/guide/java/configuration.md
index b0b2a93632..d13756360a 100644
--- a/docs/guide/java/configuration.md
+++ b/docs/guide/java/configuration.md
@@ -28,8 +28,8 @@ This page documents all configuration options available through `ForyBuilder`.
 | `timeRefIgnored`                    | Whether to ignore reference tracking of all time types registered in `TimeSerializers` and subclasses of those types when ref tracking is enabled. If ignored, ref tracking of every time type can be enabled by invoking `Fory#registerSerializer(Class, Serializer)`. For example, `fory.registerSerializer(Date.class, new DateSerializer(fory, true))`. Note that enabling ref tracking should happen before serializer codegen of any types which contain time  [...]
 | `compressInt`                       | Enables or disables int compression for smaller size.                                                                                                                                                                                                                                                                                                                                                                                                                [...]
 | `compressLong`                      | Enables or disables long compression for smaller size.                                                                                                                                                                                                                                                                                                                                                                                                               [...]
-| `compressIntArray`                  | Enables or disables SIMD-accelerated compression for int arrays when values can fit in smaller data types. Requires Java 16+.                                                                                                                                                                                                                                                                                                                                        [...]
-| `compressLongArray`                 | Enables or disables SIMD-accelerated compression for long arrays when values can fit in smaller data types. Requires Java 16+.                                                                                                                                                                                                                                                                                                                                       [...]
+| `compressIntArray`                  | Enables or disables SIMD-accelerated compression for int arrays when values can fit in smaller data types. Requires Java 16+.                                                                                                                                                                                                                                                                                                                                        [...]
+| `compressLongArray`                 | Enables or disables SIMD-accelerated compression for long arrays when values can fit in smaller data types. Requires Java 16+.                                                                                                                                                                                                                                                                                                                                       [...]
 | `compressString`                    | Enables or disables string compression for smaller size.                                                                                                                                                                                                                                                                                                                                                                                                             [...]
 | `classLoader`                       | The classloader should not be updated; Fory caches class metadata. Use `LoaderBinding` or `ThreadSafeFory` for classloader updates.                                                                                                                                                                                                                                                                                                                                  [...]
 | `compatibleMode`                    | Type forward/backward compatibility config. Also Related to `checkClassVersion` config. `SCHEMA_CONSISTENT`: Class schema must be consistent between serialization peer and deserialization peer. `COMPATIBLE`: Class schema can be different between serialization peer and deserialization peer. They can add/delete fields independently. [See more](schema-evolution.md).                                                                                        [...]
@@ -39,14 +39,14 @@ This page documents all configuration options available through `ForyBuilder`.
 | `requireClassRegistration`          | Disabling may allow unknown classes to be deserialized, potentially causing security risks.                                                                                                                                                                                                                                                                                                                                                                          [...]
 | `maxDepth`                          | Set max depth for deserialization, when depth exceeds, an exception will be thrown. This can be used to refuse deserialization DDOS attack.                                                                                                                                                                                                                                                                                                                          [...]
 | `suppressClassRegistrationWarnings` | Whether to suppress class registration warnings. The warnings can be used for security audit, but may be annoying, this suppression will be enabled by default.                                                                                                                                                                                                                                                                                                      [...]
-| `metaShareEnabled`                  | Enables or disables meta share mode.                                                                                                                                                                                                                                                                                                                                                                                                                                 [...]
-| `scopedMetaShareEnabled`            | Scoped meta share focuses on a single serialization process. Metadata created or identified during this process is exclusive to it and is not shared with by other serializations.                                                                                                                                                                                                                                                                                   [...]
+| `metaShareEnabled`                  | Enables or disables meta share mode.                                                                                                                                                                                                                                                                                                                                                                                                                                 [...]
+| `scopedMetaShareEnabled`            | Scoped meta share focuses on a single serialization process. Metadata created or identified during this process is exclusive to it and is not shared with by other serializations.                                                                                                                                                                                                                                                                                   [...]
 | `metaCompressor`                    | Set a compressor for meta compression. Note that the passed MetaCompressor should be thread-safe. By default, a `Deflater` based compressor `DeflaterMetaCompressor` will be used. Users can pass other compressor such as `zstd` for better compression rate.                                                                                                                                                                                                       [...]
-| `deserializeUnknownClass`           | Enables or disables deserialization/skipping of data for non-existent or unknown classes.                                                                                                                                                                                                                                                                                                                                                                            [...]
+| `deserializeUnknownClass`           | Enables or disables deserialization/skipping of data for non-existent or unknown classes.                                                                                                                                                                                                                                                                                                                                                                            [...]
 | `codeGenEnabled`                    | Disabling may result in faster initial serialization but slower subsequent serializations.                                                                                                                                                                                                                                                                                                                                                                           [...]
 | `asyncCompilationEnabled`           | If enabled, serialization uses interpreter mode first and switches to JIT serialization after async serializer JIT for a class is finished.                                                                                                                                                                                                                                                                                                                          [...]
 | `scalaOptimizationEnabled`          | Enables or disables Scala-specific serialization optimization.                                                                                                                                                                                                                                                                                                                                                                                                       [...]
-| `copyRef`                           | When disabled, the copy performance will be better. But fory deep copy will ignore circular and shared reference. Same reference of an object graph will be copied into different objects in one `Fory#copy`.                                                                                                                                                                                                                                                        [...]
+| `copyRef`                           | When disabled, the copy performance will be better. But fory deep copy will ignore circular and shared reference. Same reference of an object graph will be copied into different objects in one `Fory#copy`.                                                                                                                                                                                                                                                        [...]
 | `serializeEnumByName`               | When Enabled, fory serialize enum by name instead of ordinal.                                                                                                                                                                                                                                                                                                                                                                                                        [...]
 
 ## Example Configuration
diff --git a/docs/guide/java/schema-evolution.md b/docs/guide/java/schema-evolution.md
index c7db189658..4277b59d8f 100644
--- a/docs/guide/java/schema-evolution.md
+++ b/docs/guide/java/schema-evolution.md
@@ -73,7 +73,7 @@ Fory supports sharing type metadata (class name, field name, final field type in
 //   .withLanguage(Language.JAVA)
 //   .withRefTracking(false)
 //   // share meta across serialization.
-//   .withMetaContextShare(true)
+//   .withMetaShare(true)
 
 // Not thread-safe fory.
 MetaContext context = xxx;
diff --git a/docs/guide/python/configuration.md b/docs/guide/python/configuration.md
index aa71f70855..ab6d52f730 100644
--- a/docs/guide/python/configuration.md
+++ b/docs/guide/python/configuration.md
@@ -33,35 +33,37 @@ class Fory:
         ref: bool = False,
         strict: bool = True,
         compatible: bool = False,
-        max_depth: int = 50
+        max_depth: int = 50,
+        policy: DeserializationPolicy = None,
+        field_nullable: bool = False,
+        meta_compressor=None,
     )
 ```
 
 ## ThreadSafeFory Class
 
-Thread-safe serialization interface using thread-local storage:
+Thread-safe serialization interface using a pooled wrapper:
 
 ```python
 class ThreadSafeFory:
     def __init__(
-        self,
-        xlang: bool = False,
-        ref: bool = False,
-        strict: bool = True,
-        compatible: bool = False,
-        max_depth: int = 50
+        self, fory_factory=None, **kwargs
     )
 ```
 
 ## Parameters
 
-| Parameter    | Type   | Default | Description                                                                                                                                                                                |
-| ------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| `xlang`      | `bool` | `False` | Enable cross-language serialization. When `False`, enables Python-native mode supporting all Python objects. When `True`, enables cross-language mode compatible with Java, Go, Rust, etc. |
-| `ref`        | `bool` | `False` | Enable reference tracking for shared/circular references. Disable for better performance if your data has no shared references.                                                            |
-| `strict`     | `bool` | `True`  | Require type registration for security. **Highly recommended** for production. Only disable in trusted environments.                                                                       |
-| `compatible` | `bool` | `False` | Enable schema evolution in cross-language mode, allowing fields to be added/removed while maintaining compatibility.                                                                       |
-| `max_depth`  | `int`  | `50`    | Maximum deserialization depth for security, preventing stack overflow attacks.                                                                                                             |
+| Parameter         | Type                            | Default | Description                                                                                                                                                                                |
+| ----------------- | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `xlang`           | `bool`                          | `False` | Enable cross-language serialization. When `False`, enables Python-native mode supporting all Python objects. When `True`, enables cross-language mode compatible with Java, Go, Rust, etc. |
+| `ref`             | `bool`                          | `False` | Enable reference tracking for shared/circular references. Disable for better performance if your data has no shared references.                                                            |
+| `strict`          | `bool`                          | `True`  | Require type registration for security. **Highly recommended** for production. Only disable in trusted environments.                                                                       |
+| `compatible`      | `bool`                          | `False` | Enable schema evolution in cross-language mode, allowing fields to be added/removed while maintaining compatibility.                                                                       |
+| `max_depth`       | `int`                           | `50`    | Maximum deserialization depth for security, preventing stack overflow attacks.                                                                                                             |
+| `policy`          | `DeserializationPolicy \| None` | `None`  | Deserialization policy used for security checks. Strongly recommended when `strict=False`.                                                                                                 |
+| `field_nullable`  | `bool`                          | `False` | In Python-native mode (`xlang=False`), treat dataclass fields as nullable by default. Ignored in xlang mode.                                                                               |
+| `meta_compressor` | `Any`                           | `None`  | Optional metadata compressor used for compatible-mode metadata encoding.                                                                                                                   |
+| `fory_factory`    | `Callable \| None`              | `None`  | `ThreadSafeFory` factory hook. When set, `ThreadSafeFory` creates instances via this callback; otherwise it forwards `**kwargs` to `Fory` construction.                                    |
 
 ## Key Methods
 
diff --git a/docs/guide/python/index.md b/docs/guide/python/index.md
index 795fc533d2..d0580943ed 100644
--- a/docs/guide/python/index.md
+++ b/docs/guide/python/index.md
@@ -80,7 +80,7 @@ pip install -e ".[dev,format]"
 
 ## Thread Safety
 
-`pyfory` provides `ThreadSafeFory` for thread-safe serialization using thread-local storage:
+`pyfory` provides `ThreadSafeFory` for thread-safe serialization using a pooled wrapper:
 
 ```python
 import pyfory
diff --git a/docs/guide/rust/schema-evolution.md b/docs/guide/rust/schema-evolution.md
index 07d175eff5..f58db6ad0a 100644
--- a/docs/guide/rust/schema-evolution.md
+++ b/docs/guide/rust/schema-evolution.md
@@ -155,7 +155,7 @@ enum NewEvent {
     KeyPress(String),  // New variant
 }
 
-let mut fory = Fory::builder().compatible().build();
+let mut fory = Fory::default().compatible(true);
 
 // Serialize with old schema
 let old_bytes = fory.serialize(&OldEvent::Click { x: 100, y: 200 })?;
diff --git a/docs/guide/rust/type-registration.md b/docs/guide/rust/type-registration.md
index 3e5c0dec03..0c209ce552 100644
--- a/docs/guide/rust/type-registration.md
+++ b/docs/guide/rust/type-registration.md
@@ -57,7 +57,7 @@ let mut fory = Fory::default()
     .xlang(true);
 
 // Register with namespace-based naming
-fory.register_by_namespace::<MyStruct>("com.example", "MyStruct");
+fory.register_by_namespace::<MyStruct>("com.example", "MyStruct")?;
 ```
 
 ## Register Custom Serializer
@@ -66,12 +66,12 @@ For types that need custom serialization logic:
 
 ```rust
 let mut fory = Fory::default();
-fory.register_serializer::<CustomType>(100);
+fory.register_serializer::<CustomType>(100)?;
 ```
 
-## Registration Order
+## Registration Consistency
 
-When using ID-based registration without explicit IDs, the registration order matters. Ensure consistent registration order between serialization and deserialization:
+Rust registration APIs use explicit IDs or explicit namespace/type names. Keep the same registration mapping on serializer and deserializer peers:
 
 ```rust
 // Serializer side
@@ -80,7 +80,7 @@ fory.register::<TypeA>(1)?;
 fory.register::<TypeB>(2)?;
 fory.register::<TypeC>(3)?;
 
-// Deserializer side - MUST use same order
+// Deserializer side - MUST use the same ID mapping
 let mut fory = Fory::default();
 fory.register::<TypeA>(1)?;
 fory.register::<TypeB>(2)?;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org


(fory-site) 02/02: 🔄 synced local 'docs/compiler/' with remote 'docs/compiler/'

Posted by ch...@apache.org.
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

commit 4f85c20d2ec3ac159af25ade82ff99619b3176d4
Author: chaokunyang <sh...@gmail.com>
AuthorDate: Sun Feb 8 02:38:04 2026 +0000

    🔄 synced local 'docs/compiler/' with remote 'docs/compiler/'
---
 docs/compiler/generated-code.md | 729 ++++++++++++++++++++++------------------
 docs/compiler/schema-idl.md     |  77 ++---
 2 files changed, 425 insertions(+), 381 deletions(-)

diff --git a/docs/compiler/generated-code.md b/docs/compiler/generated-code.md
index 225576d85a..b433374af1 100644
--- a/docs/compiler/generated-code.md
+++ b/docs/compiler/generated-code.md
@@ -23,41 +23,47 @@ This document explains generated code for each target language.
 
 Fory IDL generated types are idiomatic in host languages and can be used directly as domain objects. Generated types also include `to/from bytes` helpers and registration helpers.
 
-All snippets are representative excerpts from real generated output.
+## Reference Schemas
 
-## Example Fory IDL Schema
+The examples below use two real schemas:
 
-The sections below use this schema:
+1. `addressbook.fdl` (explicit type IDs)
+2. `auto_id.fdl` (no explicit type IDs)
+
+### `addressbook.fdl` (excerpt)
 
 ```protobuf
-package demo;
+package addressbook;
 
-enum DeviceTier [id=100] {
-    DEVICE_TIER_UNKNOWN = 0;
-    DEVICE_TIER_TIER1 = 1;
-    DEVICE_TIER_TIER2 = 2;
-}
+option go_package = "github.com/myorg/myrepo/gen/addressbook;addressbook";
 
-message User [id=101] {
-    string id = 1;
-    string name = 2;
-    optional string email = 3;
-}
+message Person [id=100] {
+    string name = 1;
+    int32 id = 2;
 
-message SearchResponse [id=102] {
-    message Result [id=103] {
-        string url = 1;
-        string title = 2;
+    enum PhoneType [id=101] {
+        PHONE_TYPE_MOBILE = 0;
+        PHONE_TYPE_HOME = 1;
+        PHONE_TYPE_WORK = 2;
     }
-    list<Result> results = 1;
+
+    message PhoneNumber [id=102] {
+        string number = 1;
+        PhoneType phone_type = 2;
+    }
+
+    list<PhoneNumber> phones = 7;
+    Animal pet = 8;
 }
 
 message Dog [id=104] {
     string name = 1;
+    int32 bark_volume = 2;
 }
 
 message Cat [id=105] {
     string name = 1;
+    int32 lives = 2;
 }
 
 union Animal [id=106] {
@@ -65,86 +71,108 @@ union Animal [id=106] {
     Cat cat = 2;
 }
 
-message Order [id=107] {
-    string id = 1;
-    ref User customer = 2;
-    list<string> items = 3;
-    map<string, int32> quantities = 4;
-    DeviceTier tier = 5;
-    Animal pet = 6;
+message AddressBook [id=103] {
+    list<Person> people = 1;
+    map<string, Person> people_by_name = 2;
 }
 ```
 
-## Java
+### `auto_id.fdl` (excerpt)
 
-### Output Layout
+```protobuf
+package auto_id;
 
-For package `demo`, Java code is generated under `demo/`:
+enum Status {
+    UNKNOWN = 0;
+    OK = 1;
+}
 
-- `DeviceTier.java`, `User.java`, `SearchResponse.java`, `Dog.java`, `Cat.java`, `Animal.java`, `Order.java`
-- `DemoForyRegistration.java`
+message Envelope {
+    string id = 1;
 
-### Type Generation
+    message Payload {
+        int32 value = 1;
+    }
 
-Enum prefix stripping keeps scoped enum values clean:
+    union Detail {
+        Payload payload = 1;
+        string note = 2;
+    }
 
-```java
-public enum DeviceTier {
-    UNKNOWN,
-    TIER1,
-    TIER2;
+    Payload payload = 2;
+    Detail detail = 3;
+    Status status = 4;
+}
+
+union Wrapper {
+    Envelope envelope = 1;
+    string raw = 2;
 }
 ```
 
-Messages are regular Java classes with `@ForyField` metadata and Java-style getters/setters:
+## Java
+
+### Output Layout
+
+For `package addressbook`, Java output is generated under:
+
+- `<java_out>/addressbook/`
+- Type files: `AddressBook.java`, `Person.java`, `Dog.java`, `Cat.java`, `Animal.java`
+- Registration helper: `AddressbookForyRegistration.java`
+
+### Type Generation
+
+Messages generate Java classes with `@ForyField`, default constructors, getters/setters, and byte helpers:
 
 ```java
-public class Order {
-    @ForyField(id = 1)
-    private String id;
+public class Person {
+    public static enum PhoneType {
+        MOBILE,
+        HOME,
+        WORK;
+    }
 
-    @ForyField(id = 2, nullable = true, ref = true)
-    private User customer;
+    public static class PhoneNumber {
+        @ForyField(id = 1)
+        private String number;
 
-    @ForyField(id = 3)
-    private List<String> items;
+        @ForyField(id = 2)
+        private PhoneType phoneType;
 
-    @ForyField(id = 4)
-    private Map<String, Integer> quantities;
+        public byte[] toBytes() { ... }
+        public static PhoneNumber fromBytes(byte[] bytes) { ... }
+    }
 
-    @ForyField(id = 5)
-    private DeviceTier tier;
+    @ForyField(id = 1)
+    private String name;
 
-    @ForyField(id = 6)
+    @ForyField(id = 8)
     private Animal pet;
 
-    public String getId() { ... }
-    public void setId(String id) { ... }
-    public User getCustomer() { ... }
-    public void setCustomer(User customer) { ... }
-
     public byte[] toBytes() { ... }
-    public static Order fromBytes(byte[] bytes) { ... }
+    public static Person fromBytes(byte[] bytes) { ... }
 }
 ```
 
-Nested messages become static inner classes:
+Unions generate classes extending `org.apache.fory.type.union.Union`:
 
 ```java
-public class SearchResponse {
-    public static class Result { ... }
-}
-```
+public final class Animal extends Union {
+    public enum AnimalCase {
+        DOG(1),
+        CAT(2);
+        public final int id;
+        AnimalCase(int id) { this.id = id; }
+    }
 
-Unions generate explicit case APIs:
+    public static Animal ofDog(Dog v) { ... }
+    public AnimalCase getAnimalCase() { ... }
+    public int getAnimalCaseId() { ... }
 
-```java
-Animal pet = Animal.ofDog(new Dog());
-if (pet.hasDog()) {
-    Dog dog = pet.getDog();
+    public boolean hasDog() { ... }
+    public Dog getDog() { ... }
+    public void setDog(Dog v) { ... }
 }
-Animal.AnimalCase c = pet.getAnimalCase();
-int caseId = pet.getAnimalCaseId();
 ```
 
 ### Registration
@@ -152,25 +180,29 @@ int caseId = pet.getAnimalCaseId();
 Generated registration helper:
 
 ```java
-public class DemoForyRegistration {
-    public static void register(Fory fory) {
-        org.apache.fory.resolver.TypeResolver resolver = fory.getTypeResolver();
-        resolver.register(DeviceTier.class, 100L);
-        resolver.registerUnion(
-            Animal.class,
-            106L,
-            new org.apache.fory.serializer.UnionSerializer(fory, Animal.class));
-        resolver.register(User.class, 101L);
-        resolver.register(SearchResponse.class, 102L);
-        resolver.register(SearchResponse.Result.class, 103L);
-        resolver.register(Dog.class, 104L);
-        resolver.register(Cat.class, 105L);
-        resolver.register(Order.class, 107L);
-    }
+public static void register(Fory fory) {
+    org.apache.fory.resolver.TypeResolver resolver = fory.getTypeResolver();
+    resolver.registerUnion(Animal.class, 106L, new org.apache.fory.serializer.UnionSerializer(fory, Animal.class));
+    resolver.register(Person.class, 100L);
+    resolver.register(Person.PhoneType.class, 101L);
+    resolver.register(Person.PhoneNumber.class, 102L);
+    resolver.register(Dog.class, 104L);
+    resolver.register(Cat.class, 105L);
+    resolver.register(AddressBook.class, 103L);
 }
 ```
 
-If you disable auto IDs (`option enable_auto_type_id = false;`), registration switches to namespace + type name:
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs (for example from `auto_id.fdl`):
+
+```java
+resolver.register(Status.class, 1124725126L);
+resolver.registerUnion(Wrapper.class, 1471345060L, new org.apache.fory.serializer.UnionSerializer(fory, Wrapper.class));
+resolver.register(Envelope.class, 3022445236L);
+resolver.registerUnion(Envelope.Detail.class, 1609214087L, new org.apache.fory.serializer.UnionSerializer(fory, Envelope.Detail.class));
+resolver.register(Envelope.Payload.class, 2862577837L);
+```
+
+If `option enable_auto_type_id = false;` is set, registration uses namespace and type name:
 
 ```java
 resolver.register(Config.class, "myapp.models", "Config");
@@ -184,68 +216,65 @@ resolver.registerUnion(
 ### Usage
 
 ```java
-Order order = new Order();
-order.setId("o456");
-order.setCustomer(new User());
-order.setTier(DeviceTier.TIER1);
-order.setPet(Animal.ofDog(new Dog()));
+Person person = new Person();
+person.setName("Alice");
+person.setPet(Animal.ofDog(new Dog()));
 
-byte[] bytes = order.toBytes();
-Order restored = Order.fromBytes(bytes);
+byte[] data = person.toBytes();
+Person restored = Person.fromBytes(data);
 ```
 
 ## Python
 
 ### Output Layout
 
-One module is generated per package, for example `demo.py`.
+Python output is one module per schema file, for example:
+
+- `<python_out>/addressbook.py`
 
 ### Type Generation
 
-Enums are `IntEnum` values with prefix stripping:
+Unions generate a case enum plus a `Union` subclass with typed helpers:
 
 ```python
-class DeviceTier(IntEnum):
-    UNKNOWN = 0
-    TIER1 = 1
-    TIER2 = 2
-```
+class AnimalCase(Enum):
+    DOG = 1
+    CAT = 2
 
-Messages are `@pyfory.dataclass` classes:
+class Animal(Union):
+    @classmethod
+    def dog(cls, v: Dog) -> "Animal": ...
 
-```python
-@pyfory.dataclass(repr=False)
-class Order:
-    id: str = pyfory.field(id=1, default="")
-    customer: Optional[User] = pyfory.field(id=2, nullable=True, ref=True, default=None)
-    items: List[str] = pyfory.field(id=3, default_factory=list)
-    quantities: Dict[str, pyfory.int32] = pyfory.field(id=4, default_factory=dict)
-    tier: DeviceTier = pyfory.field(id=5, default=None)
-    pet: Animal = pyfory.field(id=6, default=None)
+    def case(self) -> AnimalCase: ...
+    def case_id(self) -> int: ...
 
-    def to_bytes(self) -> bytes: ...
-    @classmethod
-    def from_bytes(cls, data: bytes) -> "Order": ...
+    def is_dog(self) -> bool: ...
+    def dog_value(self) -> Dog: ...
+    def set_dog(self, v: Dog) -> None: ...
 ```
 
-Nested messages stay nested:
+Messages generate `@pyfory.dataclass` types, and nested types stay nested:
 
 ```python
 @pyfory.dataclass
-class SearchResponse:
+class Person:
+    class PhoneType(IntEnum):
+        MOBILE = 0
+        HOME = 1
+        WORK = 2
+
     @pyfory.dataclass
-    class Result:
-        url: str = pyfory.field(id=1, default="")
-        title: str = pyfory.field(id=2, default="")
-```
+    class PhoneNumber:
+        number: str = pyfory.field(id=1, default="")
+        phone_type: Person.PhoneType = pyfory.field(id=2, default=None)
 
-Unions generate case enum + typed accessors:
+    name: str = pyfory.field(id=1, default="")
+    phones: List[Person.PhoneNumber] = pyfory.field(id=7, default_factory=list)
+    pet: Animal = pyfory.field(id=8, default=None)
 
-```python
-pet = Animal.dog(Dog(name="Rex"))
-if pet.is_dog():
-    dog = pet.dog_value()
-case_id = pet.case_id()
+    def to_bytes(self) -> bytes: ...
+    @classmethod
+    def from_bytes(cls, data: bytes) -> "Person": ...
 ```
 
 ### Registration
@@ -253,18 +282,27 @@ case_id = pet.case_id()
 Generated registration function:
 
 ```python
-def register_demo_types(fory: pyfory.Fory):
-    fory.register_type(DeviceTier, type_id=100)
+def register_addressbook_types(fory: pyfory.Fory):
     fory.register_union(Animal, type_id=106, serializer=AnimalSerializer(fory))
-    fory.register_type(User, type_id=101)
-    fory.register_type(SearchResponse, type_id=102)
-    fory.register_type(SearchResponse.Result, type_id=103)
+    fory.register_type(Person, type_id=100)
+    fory.register_type(Person.PhoneType, type_id=101)
+    fory.register_type(Person.PhoneNumber, type_id=102)
     fory.register_type(Dog, type_id=104)
     fory.register_type(Cat, type_id=105)
-    fory.register_type(Order, type_id=107)
+    fory.register_type(AddressBook, type_id=103)
 ```
 
-If auto IDs are disabled:
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```python
+fory.register_type(Status, type_id=1124725126)
+fory.register_union(Wrapper, type_id=1471345060, serializer=WrapperSerializer(fory))
+fory.register_type(Envelope, type_id=3022445236)
+fory.register_union(Envelope.Detail, type_id=1609214087, serializer=Envelope.DetailSerializer(fory))
+fory.register_type(Envelope.Payload, type_id=2862577837)
+```
+
+If `option enable_auto_type_id = false;` is set:
 
 ```python
 fory.register_type(Config, namespace="myapp.models", typename="Config")
@@ -279,78 +317,68 @@ fory.register_union(
 ### Usage
 
 ```python
-order = Order(
-    id="o456",
-    customer=User(id="u1", name="Alice"),
-    items=["a", "b"],
-    quantities={"a": 1, "b": 2},
-    tier=DeviceTier.TIER1,
-    pet=Animal.dog(Dog(name="Rex")),
-)
+person = Person(name="Alice", pet=Animal.dog(Dog(name="Rex", bark_volume=10)))
 
-data = order.to_bytes()
-restored = Order.from_bytes(data)
+data = person.to_bytes()
+restored = Person.from_bytes(data)
 ```
 
 ## Rust
 
 ### Output Layout
 
-One Rust module file per package, for example `demo.rs`.
+Rust output is one module file per schema, for example:
 
-### Type Generation
+- `<rust_out>/addressbook.rs`
 
-Enums are strongly typed and use stripped, idiomatic variant names:
-
-```rust
-#[derive(ForyObject, Debug, Clone, PartialEq, Default)]
-#[repr(i32)]
-pub enum DeviceTier {
-    #[default]
-    Unknown = 0,
-    Tier1 = 1,
-    Tier2 = 2,
-}
-```
+### Type Generation
 
-Messages derive `ForyObject`:
+Unions map to Rust enums with `#[fory(id = ...)]` case attributes:
 
 ```rust
-#[derive(ForyObject, Clone, PartialEq, Default)]
-pub struct Order {
+#[derive(ForyObject, Debug, Clone, PartialEq)]
+pub enum Animal {
     #[fory(id = 1)]
-    pub id: String,
-    #[fory(id = 2, nullable = true, ref = true)]
-    pub customer: Option<Arc<User>>,
-    #[fory(id = 3)]
-    pub items: Vec<String>,
-    #[fory(id = 4)]
-    pub quantities: HashMap<String, i32>,
-    #[fory(id = 5)]
-    pub tier: DeviceTier,
-    #[fory(id = 6, type_id = "union")]
-    pub pet: Animal,
+    Dog(Dog),
+    #[fory(id = 2)]
+    Cat(Cat),
 }
 ```
 
-Nested types are generated in nested modules:
+Nested types generate nested modules:
 
 ```rust
-pub mod search_response {
+pub mod person {
     #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
-    pub struct Result { ... }
+    #[repr(i32)]
+    pub enum PhoneType {
+        #[default]
+        Mobile = 0,
+        Home = 1,
+        Work = 2,
+    }
+
+    #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+    pub struct PhoneNumber {
+        #[fory(id = 1)]
+        pub number: String,
+        #[fory(id = 2)]
+        pub phone_type: PhoneType,
+    }
 }
 ```
 
-Unions map to Rust enums with per-case IDs:
+Messages derive `ForyObject` and include `to_bytes`/`from_bytes` helpers:
 
 ```rust
-#[derive(ForyObject, Debug, Clone, PartialEq)]
-pub enum Animal {
+#[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+pub struct Person {
     #[fory(id = 1)]
-    Dog(Dog),
-    #[fory(id = 2)]
-    Cat(Cat),
+    pub name: String,
+    #[fory(id = 7)]
+    pub phones: Vec<person::PhoneNumber>,
+    #[fory(id = 8, type_id = "union")]
+    pub pet: Animal,
 }
 ```
 
@@ -360,19 +388,28 @@ Generated registration function:
 
 ```rust
 pub fn register_types(fory: &mut Fory) -> Result<(), fory::Error> {
-    fory.register::<DeviceTier>(100)?;
     fory.register_union::<Animal>(106)?;
-    fory.register::<User>(101)?;
-    fory.register::<search_response::Result>(103)?;
-    fory.register::<SearchResponse>(102)?;
+    fory.register::<person::PhoneType>(101)?;
+    fory.register::<person::PhoneNumber>(102)?;
+    fory.register::<Person>(100)?;
     fory.register::<Dog>(104)?;
     fory.register::<Cat>(105)?;
-    fory.register::<Order>(107)?;
+    fory.register::<AddressBook>(103)?;
     Ok(())
 }
 ```
 
-If auto IDs are disabled:
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```rust
+fory.register::<Status>(1124725126)?;
+fory.register_union::<Wrapper>(1471345060)?;
+fory.register::<Envelope>(3022445236)?;
+fory.register_union::<envelope::Detail>(1609214087)?;
+fory.register::<envelope::Payload>(2862577837)?;
+```
+
+If `option enable_auto_type_id = false;` is set:
 
 ```rust
 fory.register_by_namespace::<Config>("myapp.models", "Config")?;
@@ -382,108 +419,131 @@ fory.register_union_by_namespace::<Holder>("myapp.models", "Holder")?;
 ### Usage
 
 ```rust
-let order = Order {
-    id: "o456".into(),
-    customer: Some(Arc::new(User::default())),
-    items: vec!["a".into(), "b".into()],
-    quantities: HashMap::new(),
-    tier: DeviceTier::Tier1,
-    pet: Animal::Dog(Dog { name: "Rex".into() }),
+let person = Person {
+    name: "Alice".into(),
+    pet: Animal::Dog(Dog::default()),
+    ..Default::default()
 };
 
-let bytes = order.to_bytes()?;
-let restored = Order::from_bytes(&bytes)?;
+let bytes = person.to_bytes()?;
+let restored = Person::from_bytes(&bytes)?;
 ```
 
 ## C++
 
 ### Output Layout
 
-One header per package, for example `demo.h`.
+C++ output is one header per schema file, for example:
+
+- `<cpp_out>/addressbook.h`
 
 ### Type Generation
 
-Enums are generated as `enum class` with stripped names:
+Messages generate `final` classes with typed accessors and byte helpers:
 
 ```cpp
-enum class DeviceTier : int32_t {
-  UNKNOWN = 0,
-  TIER1 = 1,
-  TIER2 = 2,
+class Person final {
+ public:
+  class PhoneNumber final {
+   public:
+    const std::string& number() const;
+    std::string* mutable_number();
+    template <class Arg, class... Args>
+    void set_number(Arg&& arg, Args&&... args);
+
+    fory::Result<std::vector<uint8_t>, fory::Error> to_bytes() const;
+    static fory::Result<PhoneNumber, fory::Error> from_bytes(const std::vector<uint8_t>& data);
+  };
+
+  const std::string& name() const;
+  std::string* mutable_name();
+  template <class Arg, class... Args>
+  void set_name(Arg&& arg, Args&&... args);
+
+  const Animal& pet() const;
+  Animal* mutable_pet();
 };
-FORY_ENUM(demo::DeviceTier, UNKNOWN, TIER1, TIER2);
 ```
 
-Messages are generated as classes with typed accessors and private fields, including `has_xxx`, `mutable_xxx`, and `set_xxx` where applicable:
+Optional message fields generate `has_xxx`, `mutable_xxx`, and `clear_xxx` APIs:
 
 ```cpp
-class Order final {
+class Envelope final {
  public:
-  const std::string& id() const;
-  std::string* mutable_id();
-  template <class Arg, class... Args>
-  void set_id(Arg&& arg, Args&&... args);
-
-  bool has_customer() const;
-  const std::shared_ptr<User>& customer() const;
-  std::shared_ptr<User>* mutable_customer();
-  void set_customer(std::shared_ptr<User> value);
-  void clear_customer();
-
-  fory::Result<std::vector<uint8_t>, fory::Error> to_bytes() const;
-  static fory::Result<Order, fory::Error> from_bytes(
-      const std::vector<uint8_t>& data);
+  bool has_payload() const { return payload_ != nullptr; }
+  const Envelope::Payload& payload() const { return *payload_; }
+  Envelope::Payload* mutable_payload() {
+    if (!payload_) {
+      payload_ = std::make_unique<Envelope::Payload>();
+    }
+    return payload_.get();
+  }
+  void clear_payload() { payload_.reset(); }
 
  private:
-  std::string id_;
-  std::shared_ptr<User> customer_;
-  std::vector<std::string> items_;
-  std::map<std::string, int32_t> quantities_;
-  DeviceTier tier_;
-  Animal pet_;
-
- public:
-  FORY_STRUCT(Order, id_, customer_, items_, quantities_, tier_, pet_);
+  std::unique_ptr<Envelope::Payload> payload_;
 };
 ```
 
-Nested messages are nested classes:
+Unions generate `std::variant` wrappers:
 
 ```cpp
-class SearchResponse final {
+class Animal final {
  public:
-  class Result final { ... };
-};
-```
+  enum class AnimalCase : uint32_t {
+    DOG = 1,
+    CAT = 2,
+  };
 
-Unions are generated as tagged `std::variant` wrappers:
+  static Animal dog(Dog v);
+  static Animal cat(Cat v);
 
-```cpp
-Animal pet = Animal::dog(Dog{});
-if (pet.is_dog()) {
-  const Dog& dog = pet.dog();
-}
-uint32_t case_id = pet.animal_case_id();
+  AnimalCase animal_case() const noexcept;
+  uint32_t animal_case_id() const noexcept;
+
+  bool is_dog() const noexcept;
+  const Dog* as_dog() const noexcept;
+  Dog* as_dog() noexcept;
+  const Dog& dog() const;
+  Dog& dog();
+
+  template <class Visitor>
+  decltype(auto) visit(Visitor&& vis) const;
+
+ private:
+  std::variant<Dog, Cat> value_;
+};
 ```
 
+Generated headers also include `FORY_UNION`, `FORY_FIELD_CONFIG`, `FORY_ENUM`, and `FORY_STRUCT` macros for serialization metadata.
+
 ### Registration
 
 Generated registration function:
 
 ```cpp
 inline void register_types(fory::serialization::BaseFory& fory) {
-  fory.register_enum<DeviceTier>(100);
-  fory.register_union<Animal>(106);
-  fory.register_struct<User>(101);
-  fory.register_struct<SearchResponse::Result>(103);
-  fory.register_struct<SearchResponse>(102);
-  fory.register_struct<Dog>(104);
-  fory.register_struct<Cat>(105);
-  fory.register_struct<Order>(107);
+    fory.register_union<Animal>(106);
+    fory.register_enum<Person::PhoneType>(101);
+    fory.register_struct<Person::PhoneNumber>(102);
+    fory.register_struct<Person>(100);
+    fory.register_struct<Dog>(104);
+    fory.register_struct<Cat>(105);
+    fory.register_struct<AddressBook>(103);
 }
 ```
 
-If auto IDs are disabled:
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```cpp
+fory.register_enum<Status>(1124725126);
+fory.register_union<Wrapper>(1471345060);
+fory.register_struct<Envelope>(3022445236);
+fory.register_union<Envelope::Detail>(1609214087);
+fory.register_struct<Envelope::Payload>(2862577837);
+```
+
+If `option enable_auto_type_id = false;` is set:
 
 ```cpp
 fory.register_struct<Config>("myapp.models", "Config");
@@ -493,96 +553,73 @@ fory.register_union<Holder>("myapp.models", "Holder");
 ### Usage
 
 ```cpp
-demo::Order order;
-order.set_id("o456");
-order.set_customer(std::make_shared<demo::User>());
+addressbook::Person person;
+person.set_name("Alice");
+*person.mutable_pet() = addressbook::Animal::dog(addressbook::Dog{});
 
-auto bytes_result = order.to_bytes();
-if (!bytes_result.ok()) {
-  return 1;
-}
-auto order_result = demo::Order::from_bytes(bytes_result.value());
-if (!order_result.ok()) {
-  return 1;
-}
-demo::Order restored = std::move(order_result.value());
+auto bytes = person.to_bytes();
+auto restored = addressbook::Person::from_bytes(bytes.value());
 ```
 
 ## Go
 
 ### Output Layout
 
-Go output path depends on whether `go_package` is configured.
-
-When `go_package` is set in schema options (as in `integration_tests/idl_tests/idl/addressbook.fdl`), output follows that package path, for example:
-
-- `integration_tests/idl_tests/go/addressbook/generated/addressbook.go`
-
-Without `go_package`, compiler derives output from the Fory IDL package name.
+Go output path depends on schema options and `--go_out`.
 
-For package `demo`, output is:
+For `addressbook.fdl`, `go_package` is configured and generated output follows the configured import path/package (for example under your `--go_out` root).
 
-- `<go_out>/demo/demo.go`
-
-For package `myapp.models`, output is:
-
-- `<go_out>/models/myapp_models.go`
+Without `go_package`, output uses the requested `--go_out` directory and package-derived file naming.
 
 ### Type Generation
 
-Enums keep Go-style unscoped constant names:
+Nested types use underscore naming by default (`Person_PhoneType`, `Person_PhoneNumber`):
 
 ```go
-type DeviceTier int32
+type Person_PhoneType int32
 
 const (
-    DeviceTierUnknown DeviceTier = 0
-    DeviceTierTier1   DeviceTier = 1
-    DeviceTierTier2   DeviceTier = 2
+    Person_PhoneTypeMobile Person_PhoneType = 0
+    Person_PhoneTypeHome   Person_PhoneType = 1
+    Person_PhoneTypeWork   Person_PhoneType = 2
 )
+
+type Person_PhoneNumber struct {
+    Number    string           `fory:"id=1"`
+    PhoneType Person_PhoneType `fory:"id=2"`
+}
 ```
 
-Messages are regular structs with fory tags:
+Messages generate structs with `fory` tags and byte helpers:
 
 ```go
-type User struct {
-    Id    string                    `fory:"id=1"`
-    Name  string                    `fory:"id=2"`
-    Email optional.Optional[string] `fory:"id=3,nullable"`
+type Person struct {
+    Name   string               `fory:"id=1"`
+    Id     int32                `fory:"id=2,compress=true"`
+    Phones []Person_PhoneNumber `fory:"id=7"`
+    Pet    Animal               `fory:"id=8"`
 }
 
-type Order struct {
-    Id         string            `fory:"id=1"`
-    Customer   *User             `fory:"id=2,nullable,ref"`
-    Items      []string          `fory:"id=3"`
-    Quantities map[string]int32  `fory:"id=4"`
-    Tier       DeviceTier        `fory:"id=5"`
-    Pet        Animal            `fory:"id=6"`
-}
+func (m *Person) ToBytes() ([]byte, error) { ... }
+func (m *Person) FromBytes(data []byte) error { ... }
 ```
 
-Nested type naming defaults to underscore:
+Unions generate typed case structs with constructors/accessors/visitor APIs:
 
 ```go
-type SearchResponse_Result struct { ... }
-```
-
-You can switch to concatenated names with:
+type AnimalCase uint32
 
-```protobuf
-option go_nested_type_style = "camelcase";
-```
+type Animal struct {
+    case_ AnimalCase
+    value any
+}
 
-Unions generate typed case helpers:
+func DogAnimal(v *Dog) Animal { ... }
+func CatAnimal(v *Cat) Animal { ... }
 
-```go
-pet := DogAnimal(&Dog{Name: "Rex"})
-if dog, ok := pet.AsDog(); ok {
-    _ = dog
-}
-_ = pet.Visit(AnimalVisitor{
-    Dog: func(d *Dog) error { return nil },
-})
+func (u Animal) Case() AnimalCase { ... }
+func (u Animal) AsDog() (*Dog, bool) { ... }
+func (u Animal) Visit(visitor AnimalVisitor) error { ... }
 ```
 
 ### Registration
@@ -591,44 +628,58 @@ Generated registration function:
 
 ```go
 func RegisterTypes(f *fory.Fory) error {
-    if err := f.RegisterEnum(DeviceTier(0), 100); err != nil {
+    if err := f.RegisterUnion(Animal{}, 106, fory.NewUnionSerializer(...)); err != nil {
         return err
     }
-    if err := f.RegisterUnion(Animal{}, 106, ...); err != nil {
+    if err := f.RegisterEnum(Person_PhoneType(0), 101); err != nil {
         return err
     }
-    if err := f.RegisterStruct(User{}, 101); err != nil {
+    if err := f.RegisterStruct(Person_PhoneNumber{}, 102); err != nil {
+        return err
+    }
+    if err := f.RegisterStruct(Person{}, 100); err != nil {
         return err
     }
-    // ... SearchResponse_Result, SearchResponse, Dog, Cat, Order
     return nil
 }
 ```
 
-If auto IDs are disabled:
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```go
+if err := f.RegisterEnum(Status(0), 1124725126); err != nil { ... }
+if err := f.RegisterUnion(Wrapper{}, 1471345060, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope{}, 3022445236); err != nil { ... }
+if err := f.RegisterUnion(Envelope_Detail{}, 1609214087, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope_Payload{}, 2862577837); err != nil { ... }
+```
+
+If `option enable_auto_type_id = false;` is set:
 
 ```go
 if err := f.RegisterNamedStruct(Config{}, "myapp.models.Config"); err != nil { ... }
-if err := f.RegisterNamedUnion(Holder{}, "myapp.models.Holder", ...); err != nil { ... }
+if err := f.RegisterNamedUnion(Holder{}, "myapp.models.Holder", fory.NewUnionSerializer(...)); err != nil { ... }
+```
+
+`go_nested_type_style` controls nested type naming:
+
+```protobuf
+option go_nested_type_style = "camelcase";
 ```
 
 ### Usage
 
 ```go
-email := optional.Some("alice@example.com")
-order := &Order{
-    Id:       "o456",
-    Customer: &User{Id: "u1", Name: "Alice", Email: email},
-    Items:    []string{"a", "b"},
-    Tier:     DeviceTierTier1,
-    Pet:      DogAnimal(&Dog{Name: "Rex"}),
+person := &Person{
+    Name: "Alice",
+    Pet:  DogAnimal(&Dog{Name: "Rex"}),
 }
 
-data, err := order.ToBytes()
+data, err := person.ToBytes()
 if err != nil {
     panic(err)
 }
-var restored Order
+var restored Person
 if err := restored.FromBytes(data); err != nil {
     panic(err)
 }
@@ -638,16 +689,26 @@ if err := restored.FromBytes(data); err != nil {
 
 ### Type ID Behavior
 
-- Explicit `[id=...]` is used directly.
-- Without explicit IDs, compiler-generated IDs are used by default.
-- With `option enable_auto_type_id = false;`, generated code registers by namespace + type name.
-
-### Nested Type Shapes
-
-| Language | Nested Type Form        |
-| -------- | ----------------------- |
-| Java     | `Outer.Inner`           |
-| Python   | `Outer.Inner`           |
-| Rust     | `outer::Inner`          |
-| C++      | `Outer::Inner`          |
-| Go       | `Outer_Inner` (default) |
+- Explicit `[id=...]` values are used directly in generated registration.
+- When type IDs are omitted, generated code uses computed numeric IDs (see `auto_id.*` outputs).
+- If `option enable_auto_type_id = false;` is set, generated registration uses namespace/type-name APIs instead of numeric IDs.
+
+### Nested Type Shape
+
+| Language | Nested type form               |
+| -------- | ------------------------------ |
+| Java     | `Person.PhoneNumber`           |
+| Python   | `Person.PhoneNumber`           |
+| Rust     | `person::PhoneNumber`          |
+| C++      | `Person::PhoneNumber`          |
+| Go       | `Person_PhoneNumber` (default) |
+
+### Byte Helper Naming
+
+| Language | Helpers                   |
+| -------- | ------------------------- |
+| Java     | `toBytes` / `fromBytes`   |
+| Python   | `to_bytes` / `from_bytes` |
+| Rust     | `to_bytes` / `from_bytes` |
+| C++      | `to_bytes` / `from_bytes` |
+| Go       | `ToBytes` / `FromBytes`   |
diff --git a/docs/compiler/schema-idl.md b/docs/compiler/schema-idl.md
index 869187cd0e..4e297aa770 100644
--- a/docs/compiler/schema-idl.md
+++ b/docs/compiler/schema-idl.md
@@ -272,30 +272,15 @@ message Payment {
 }
 ```
 
-### Protobuf Compatibility Options
+### Protobuf Extension Syntax
 
-Fory IDL accepts protobuf-style extension syntax (for example, `(fory).id`) for
-compatibility, but native Fory IDL style uses plain option keys such as `id`,
-`evolving`, `ref`, and `nullable` without the `(fory)` prefix.
+In `.fdl` files, use native Fory IDL syntax only (for example, `[id=100]`, `ref`,
+`optional`, `nullable=true`).
 
-Equivalent forms:
+Protobuf extension syntax with `(fory).` is for `.proto` files and the protobuf
+frontend only.
 
-```protobuf
-// Native Fory IDL style (preferred in .fdl files)
-message Node [id=100] {
-    ref Node parent = 1;
-    optional string nickname = 2;
-}
-
-// Protobuf-style compatibility syntax
-message Node {
-    option (fory).id = 100;
-    Node parent = 1 [(fory).ref = true];
-    string nickname = 2 [(fory).nullable = true];
-}
-```
-
-For the protobuf-specific extension option guide, see
+For protobuf extension options, see
 [Protocol Buffers IDL Support](protobuf-idl.md#fory-extension-options-protobuf).
 
 ### Option Priority
@@ -474,21 +459,22 @@ enum Status {
 }
 ```
 
-### Enum Options
+### Enum Type Options
 
-Options can be specified within enums:
+Enum-level options are declared inline in `[]` after the enum name:
 
 ```protobuf
-enum Status {
-    option deprecated = true;  // Allowed
+enum Status [deprecated=true] {
     PENDING = 0;
     ACTIVE = 1;
 }
 ```
 
-**Forbidden Options:**
+FDL does not support `option ...;` statements inside enum bodies.
+
+**Unsupported:**
 
-- `option allow_alias = true` is **not supported**. Each enum value must have a unique integer.
+- `allow_alias` is **not supported**. Each enum value must have a unique integer.
 
 ### Language Mapping
 
@@ -531,8 +517,7 @@ enum DeviceTier {
 enum_def     := 'enum' IDENTIFIER [type_options] '{' enum_body '}'
 type_options := '[' type_option (',' type_option)* ']'
 type_option  := IDENTIFIER '=' option_value
-enum_body    := (option_stmt | reserved_stmt | enum_value)*
-option_stmt  := 'option' IDENTIFIER '=' option_value ';'
+enum_body    := (reserved_stmt | enum_value)*
 reserved_stmt := 'reserved' reserved_items ';'
 enum_value   := IDENTIFIER '=' INTEGER ';'
 ```
@@ -616,26 +601,27 @@ message User {
 }
 ```
 
-### Message Options
+### Message Type Options
 
-Options can be specified within messages:
+Message-level options are declared inline in `[]` after the message name:
 
 ```protobuf
-message User {
-    option deprecated = true;
+message User [deprecated=true] {
     string id = 1;
     string name = 2;
 }
 ```
 
+FDL does not support `option ...;` statements inside message or enum bodies.
+
 **Grammar:**
 
 ```
 message_def  := 'message' IDENTIFIER [type_options] '{' message_body '}'
 type_options := '[' type_option (',' type_option)* ']'
 type_option  := IDENTIFIER '=' option_value
-message_body := (option_stmt | reserved_stmt | nested_type | field_def)*
-nested_type  := enum_def | message_def
+message_body := (reserved_stmt | nested_type | field_def)*
+nested_type  := enum_def | message_def | union_def
 ```
 
 **Rules:**
@@ -644,7 +630,7 @@ nested_type  := enum_def | message_def
 
 ## Nested Types
 
-Messages can contain nested message and enum definitions. This is useful for defining types that are closely related to their parent message.
+Messages can contain nested message, enum, and union definitions. This is useful for defining types that are closely related to their parent message.
 
 ### Nested Messages
 
@@ -722,7 +708,7 @@ message OtherMessage {
 | Rust     | Nested modules (`search_response::Result`)                                        |
 | C++      | Nested classes (`SearchResponse::Result`)                                         |
 
-**Note:** Go defaults to underscore-separated nested names; set `option (fory).go_nested_type_style = "camelcase";` to use concatenated names. Rust emits nested modules for nested types.
+**Note:** Go defaults to underscore-separated nested names; set `option go_nested_type_style = "camelcase";` to use concatenated names. Rust emits nested modules for nested types.
 
 ### Nested Type Rules
 
@@ -1361,33 +1347,30 @@ package_decl := 'package' package_name ['alias' package_name] ';'
 package_name := IDENTIFIER ('.' IDENTIFIER)*
 
 file_option  := 'option' option_name '=' option_value ';'
-option_name  := IDENTIFIER | extension_name
-extension_name := '(' IDENTIFIER ')' '.' IDENTIFIER   // e.g., (fory).polymorphism
+option_name  := IDENTIFIER
 
 import_decl  := 'import' STRING ';'
 
 type_def     := enum_def | message_def | union_def
 
 enum_def     := 'enum' IDENTIFIER [type_options] '{' enum_body '}'
-enum_body    := (option_stmt | reserved_stmt | enum_value)*
+enum_body    := (reserved_stmt | enum_value)*
 enum_value   := IDENTIFIER '=' INTEGER ';'
 
 message_def  := 'message' IDENTIFIER [type_options] '{' message_body '}'
-message_body := (option_stmt | reserved_stmt | nested_type | field_def)*
-nested_type  := enum_def | message_def
+message_body := (reserved_stmt | nested_type | field_def)*
+nested_type  := enum_def | message_def | union_def
 field_def    := [modifiers] field_type IDENTIFIER '=' INTEGER [field_options] ';'
 
 union_def    := 'union' IDENTIFIER [type_options] '{' union_field* '}'
-union_field  := field_type IDENTIFIER '=' INTEGER ';'
-
-option_stmt  := 'option' option_name '=' option_value ';'
+union_field  := ['repeated'] field_type IDENTIFIER '=' INTEGER [field_options] ';'
 option_value := 'true' | 'false' | IDENTIFIER | INTEGER | STRING
 
 reserved_stmt := 'reserved' reserved_items ';'
 reserved_items := reserved_item (',' reserved_item)*
 reserved_item := INTEGER | INTEGER 'to' INTEGER | INTEGER 'to' 'max' | STRING
 
-modifiers    := { 'optional' | 'ref' } ['list' { 'optional' | 'ref' }]
+modifiers    := { 'optional' | 'ref' | 'repeated' }
 
 field_type   := primitive_type | named_type | list_type | map_type
 primitive_type := 'bool'
@@ -1407,7 +1390,7 @@ map_type     := 'map' '<' field_type ',' field_type '>'
 type_options := '[' type_option (',' type_option)* ']'
 type_option  := IDENTIFIER '=' option_value         // e.g., id=100, deprecated=true
 field_options := '[' field_option (',' field_option)* ']'
-field_option := option_name '=' option_value        // e.g., deprecated=true, (fory).ref=true
+field_option := IDENTIFIER '=' option_value         // e.g., deprecated=true, ref=true
 
 STRING       := '"' [^"\n]* '"' | "'" [^'\n]* "'"
 IDENTIFIER   := [a-zA-Z_][a-zA-Z0-9_]*


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org