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


The following commit(s) were added to refs/heads/main by this push:
     new 94a8583b 🔄 synced local 'docs/guide/' with remote 'docs/guide/'
94a8583b is described below

commit 94a8583b6923127727162ace0c0a95d6b4b02a41
Author: chaokunyang <[email protected]>
AuthorDate: Wed Jun 18 12:20:16 2025 +0000

    🔄 synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/DEVELOPMENT.md              |  15 +
 docs/guide/java_serialization_guide.md | 817 ++++++++++++++++++++++++++++++++-
 2 files changed, 819 insertions(+), 13 deletions(-)

diff --git a/docs/guide/DEVELOPMENT.md b/docs/guide/DEVELOPMENT.md
index dffe0995..0379d9f6 100644
--- a/docs/guide/DEVELOPMENT.md
+++ b/docs/guide/DEVELOPMENT.md
@@ -120,3 +120,18 @@ npm run test
 
 - node 14+
 - npm 8+
+
+### Lint Markdown Docs
+
+```bash
+# Install prettier globally
+npm install -g prettier
+
+# Fix markdown files
+prettier --write "**/*.md"
+```
+
+#### Environment Requirements
+
+- node 14+
+- npm 8+
diff --git a/docs/guide/java_serialization_guide.md 
b/docs/guide/java_serialization_guide.md
index af85d1bb..728b5f1c 100644
--- a/docs/guide/java_serialization_guide.md
+++ b/docs/guide/java_serialization_guide.md
@@ -108,10 +108,10 @@ public class Example {
 }
 ```
 
-## ForyBuilder  options
+## ForyBuilder options
 
 | Option Name                         | Description                            
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
+| ----------------------------------- | 
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
 | `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.                                                               
                                                                                
                                                                                
                                                                                
                                                                                
                [...]
@@ -211,8 +211,7 @@ sophisticated compression techniques to minimize overhead, 
there is still some a
 class metadata.
 
 To further reduce metadata costs, Fory introduces a class metadata sharing 
mechanism, which allows the metadata to be
-sent to the deserialization process only once. For more details, please refer 
to the [Meta Sharing](#MetaSharing)
-section.
+sent to the deserialization process only once. For more details, please refer 
to the [Meta 
Sharing](https://fory.apache.org/docs/specification/fory_java_serialization_spec#meta-share)
 specification.
 
 ### Smaller size
 
@@ -234,9 +233,9 @@ For long compression, fory support two encoding:
   - Otherwise write as 9 bytes: `| 0b1 | little-endian 8bytes long |`
 - Fory PVL(Progressive Variable-length Long) Encoding:
   - First bit in every byte indicate whether has next byte. if first bit is 
set, then next byte will be read util
-      first bit of next byte is unset.
+    first bit of next byte is unset.
   - Negative number will be converted to positive number by `(v << 1) ^ (v >> 
63)` to reduce cost of small negative
-      numbers.
+    numbers.
 
 If a number are `long` type, it can't be represented by smaller bytes mostly, 
the compression won't get good enough
 result,
@@ -266,10 +265,8 @@ SomeClass copied = fory.copy(a);
 ### Implement a customized serializer
 
 In some cases, you may want to implement a serializer for your type, 
especially some class customize serialization by
-JDK
-writeObject/writeReplace/readObject/readResolve, which is very inefficient. 
For example, you don't want
-following `Foo#writeObject`
-got invoked, you can take following `FooSerializer` as an example:
+JDK `writeObject/writeReplace/readObject/readResolve`, which is very 
inefficient. For example, if you don't want
+following `Foo#writeObject` got invoked, you can take following 
`FooSerializer` as an example:
 
 ```java
 class Foo {
@@ -307,6 +304,799 @@ Fory fory = getFory();
 fory.registerSerializer(Foo.class, new FooSerializer(fory));
 ```
 
+### Implement Collection Serializer
+
+Similar to maps, when implementing a serializer for a custom Collection type, 
you must extend `CollectionSerializer` or `AbstractCollectionSerializer`.
+The key difference between these two is that `AbstractCollectionSerializer` 
can serialize a class which has a collection-like structure but is not a java 
Collection subtype.
+
+For collection serializer, this is a special parameter `supportCodegenHook` 
needs be configured:
+
+- When `true`:
+
+  - Enables optimized access to collection elements and JIT compilation for 
better performance
+  - Direct serialization invocation and inline for map key-value items without 
dynamic serializer dispatch cost.
+  - Better performance for standard collection types
+  - Recommended for most collections
+
+- When `false`:
+  - Uses interfaced-based element access and dynamic serializer dispatch for 
elements, which have higer cost
+  - More flexible for custom collection types
+  - Required when collection has special serialization needs
+  - Handles complex collection implementations
+
+#### Implement Collection Serializer with JIT support
+
+When implementing a Collection serializer with JIT support, you can leverage 
Fory's existing binary format and collection serialization infrastructure. The 
key is to properly implement the `onCollectionWrite` and `newCollection` 
methods to handle metadata while letting Fory handle the element serialization.
+
+Here's an example:
+
+```java
+public class CustomCollectionSerializer<T extends Collection> extends 
CollectionSerializer<T> {
+    public CustomCollectionSerializer(Fory fory, Class<T> cls) {
+        // supportCodegenHook controls whether to use JIT compilation
+        super(fory, cls, true);
+    }
+
+    @Override
+    public Collection onCollectionWrite(MemoryBuffer buffer, T value) {
+        // Write collection size
+        buffer.writeVarUint32Small7(value.size());
+        // Write any additional collection metadata
+        return value;
+    }
+
+    @Override
+    public Collection newCollection(MemoryBuffer buffer) {
+        // Create new collection instance
+        Collection collection = super.newCollection(buffer);
+        // Read and set collection size
+        int numElements = getAndClearNumElements();
+        setNumElements(numElements);
+        return collection;
+    }
+}
+```
+
+Note that please invoke `setNumElements` when implementing `newCollection` to 
let fory know how many elements to deserialize.
+
+#### Implement a totally-customzied Collection Serializer without JIT
+
+Sometimes you need to serialize a collection type that uses primitive arrays 
or has special requirements.
+In such cases, you can implement a serializer with JIT disabled and directly 
override the `write` and `read` methods.
+
+This approach:
+
+- Gives you full control over serialization
+- Works well with primitive arrays
+- Bypasses collection iteration overhead
+- Allows direct memory access
+
+Here's an example of a custom integer list backed by a primitive array:
+
+```java
+class IntList extends AbstractCollection<Integer> {
+    private final int[] elements;
+    private final int size;
+
+    public IntList(int size) {
+        this.elements = new int[size];
+        this.size = size;
+    }
+
+    public IntList(int[] elements, int size) {
+        this.elements = elements;
+        this.size = size;
+    }
+
+    @Override
+    public Iterator<Integer> iterator() {
+        return new Iterator<Integer>() {
+            private int index = 0;
+
+            @Override
+            public boolean hasNext() {
+                return index < size;
+            }
+
+            @Override
+            public Integer next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                return elements[index++];
+            }
+        };
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    public int get(int index) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException();
+        }
+        return elements[index];
+    }
+
+    public void set(int index, int value) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException();
+        }
+        elements[index] = value;
+    }
+
+    public int[] getElements() {
+        return elements;
+    }
+}
+
+class IntListSerializer extends AbstractCollectionSerializer<IntList> {
+    public IntListSerializer(Fory fory) {
+        // Disable JIT since we're handling serialization directly
+        super(fory, IntList.class, false);
+    }
+
+    @Override
+    public void write(MemoryBuffer buffer, IntList value) {
+        // Write size
+        buffer.writeVarUint32Small7(value.size());
+
+        // Write elements directly as primitive ints
+        int[] elements = value.getElements();
+        for (int i = 0; i < value.size(); i++) {
+            buffer.writeVarInt32(elements[i]);
+        }
+    }
+
+    @Override
+    public IntList read(MemoryBuffer buffer) {
+        // Read size
+        int size = buffer.readVarUint32Small7();
+
+        // Create array and read elements
+        int[] elements = new int[size];
+        for (int i = 0; i < size; i++) {
+            elements[i] = buffer.readVarInt32();
+        }
+
+        return new IntList(elements, size);
+    }
+
+    // These methods are not used when JIT is disabled
+    @Override
+    public Collection onCollectionWrite(MemoryBuffer buffer, IntList value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection newCollection(MemoryBuffer buffer) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntList onCollectionRead(Collection collection) {
+        throw new UnsupportedOperationException();
+    }
+}
+```
+
+Key Points:
+
+1. **Primitive Array Storage**:
+
+   - Uses `int[]` for direct storage
+   - Avoids boxing/unboxing overhead
+   - Provides efficient memory layout
+   - Enables direct array access
+
+2. **Direct Serialization**:
+
+   - Write size first
+   - Write primitive values directly
+   - No iteration overhead
+   - No boxing/unboxing during serialization
+
+3. **Direct Deserialization**:
+
+   - Read size first
+   - Create primitive array
+   - Read values directly into array
+   - Create list with populated array
+
+4. **Disabled JIT**:
+   - Set `supportCodegenHook=false`
+   - Override `write`/`read` methods
+   - Skip collection view pattern
+   - Full control over serialization format
+
+When to Use: this approach is best when:
+
+- Working with primitive types
+- Need maximum performance
+- Want to minimize memory overhead
+- Have special serialization requirements
+
+Usage Example:
+
+```java
+// Create and populate list
+IntList list = new IntList(3);
+list.set(0, 1);
+list.set(1, 2);
+list.set(2, 3);
+
+// Serialize
+byte[] bytes = fory.serialize(list);
+
+// Deserialize
+IntList newList = (IntList) fory.deserialize(bytes);
+```
+
+This implementation is particularly efficient for scenarios where:
+
+- You're working exclusively with integers
+- Performance is critical
+- Memory efficiency is important
+- Serialization overhead needs to be minimized
+
+Remember that while this approach gives up some of Fory's optimizations, it 
can provide better performance for specific use cases involving primitive types 
and direct array access.
+
+#### Implement Serializer for Collection-like Types
+
+Sometimes you may want to implement a serializer for a type that behaves like 
a collection but isn't a standard Java Collection. This section demonstrates 
how to implement a serializer for such types.
+
+The key principles for collection-like type serialization are:
+
+1. Extend `AbstractCollectionSerializer` for custom collection-like types
+2. Enable JIT optimization with `supportCodegenHook`
+3. Provide efficient element access through views
+4. Maintain proper size tracking
+
+Here's an example:
+
+```java
+class CustomCollectionLike {
+    private final Object[] elements;
+    private final int size;
+
+    public CustomCollectionLike(int size) {
+        this.elements = new Object[size];
+        this.size = size;
+    }
+
+    // Constructor for wrapping existing array
+    public CustomCollectionLike(Object[] elements, int size) {
+        this.elements = elements;
+        this.size = size;
+    }
+
+    public Object get(int index) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException();
+        }
+        return elements[index];
+    }
+
+    public int size() {
+        return size;
+    }
+
+    public Object[] getElements() {
+        return elements;
+    }
+}
+
+// A view class that extends AbstractCollection for simpler implementation
+class CollectionView extends AbstractCollection<Object> {
+    private final Object[] elements;
+    private final int size;
+    private int writeIndex;
+
+    // Constructor for serialization (wrapping existing array)
+    public CollectionView(CustomCollectionLike collection) {
+        this.elements = collection.getElements();
+        this.size = collection.size();
+    }
+
+    // Constructor for deserialization
+    public CollectionView(int size) {
+        this.size = size;
+        this.elements = new Object[size];
+    }
+
+    @Override
+    public Iterator<Object> iterator() {
+        return new Iterator<Object>() {
+            private int index = 0;
+
+            @Override
+            public boolean hasNext() {
+                return index < size;
+            }
+
+            @Override
+            public Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                return elements[index++];
+            }
+        };
+    }
+
+    @Override
+    public boolean add(Object element) {
+        if (writeIndex >= size) {
+            throw new IllegalStateException("Collection is full");
+        }
+        elements[writeIndex++] = element;
+        return true;
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    public Object[] getElements() {
+        return elements;
+    }
+}
+
+class CustomCollectionSerializer extends 
AbstractCollectionSerializer<CustomCollectionLike> {
+    public CustomCollectionSerializer(Fory fory) {
+        super(fory, CustomCollectionLike.class, true);
+    }
+
+    @Override
+    public Collection onCollectionWrite(MemoryBuffer buffer, 
CustomCollectionLike value) {
+        buffer.writeVarUint32Small7(value.size());
+        return new CollectionView(value);
+    }
+
+    @Override
+    public Collection newCollection(MemoryBuffer buffer) {
+        int numElements = buffer.readVarUint32Small7();
+        setNumElements(numElements);
+        return new CollectionView(numElements);
+    }
+
+    @Override
+    public CustomCollectionLike onCollectionRead(Collection collection) {
+        CollectionView view = (CollectionView) collection;
+        return new CustomCollectionLike(view.getElements(), view.size());
+    }
+}
+```
+
+Key takeways:
+
+1. **Collection Structure**:
+
+   - Array-based storage for elements
+   - Fixed size after creation
+   - Direct element access
+   - Size tracking
+
+2. **View Implementation**:
+
+   - Extends `AbstractCollection` for simplicity
+   - Provides iterator for element access
+   - Implements `add()` for deserialization
+   - Shares array reference with original type
+
+3. **Serializer Features**:
+
+   - Uses `supportCodegenHook=true` for JIT optimization
+   - Shares array references when possible
+   - Maintains proper size tracking
+   - Uses view pattern for serialization
+
+4. **Performance Aspects**:
+   - Direct array access
+   - Minimal object creation
+   - Array sharing between instances
+   - Efficient iteration
+
+Note that this implementation provides better performance at the cost of 
flexibility. Consider your specific use case when choosing this approach.
+
+### Implement Map Serializer
+
+When implementing a serializer for a custom Map type, you must extend 
`MapSerializer` or `AbstractMapSerializer`. The key difference between these 
two is that `AbstractMapSerializer` can serialize a class which has a map-like 
structure but is not a java Map subtype.
+
+Similiar to collection serializer, this is a special parameter 
`supportCodegenHook` needs be configured:
+
+- When `true`:
+
+  - Enables optimized access to map elements and JIT compilation for better 
performance
+  - Direct serialization invocation and inline for map key-value items without 
dynamic serializer dispatch cost.
+  - Better performance for standard map types
+  - Recommended for most maps
+
+- When `false`:
+  - Uses interfaced-based element access and dynamic serializer dispatch for 
elements, which have higer cost
+  - More flexible for custom map types
+  - Required when map has special serialization needs
+  - Handles complex map implementations
+
+#### Implement Map Serializer with JIT support
+
+When implementing a Map serializer with JIT support, you can leverage Fory's 
existing chunk-based binary format and map serialization infrastructure. The 
key is to properly implement the `onMapWrite` and `newMap` methods to handle 
metadata while letting Fory handle the map key-value serialization.
+
+Here's an example of implementing a custom map serializer:
+
+```java
+public class CustomMapSerializer<T extends Map> extends MapSerializer<T> {
+    public CustomMapSerializer(Fory fory, Class<T> cls) {
+        // supportCodegenHook is a critical parameter that determines 
serialization behavior
+        super(fory, cls, true);
+    }
+
+    @Override
+    public Map onMapWrite(MemoryBuffer buffer, T value) {
+        // Write map size
+        buffer.writeVarUint32Small7(value.size());
+        // Write any additional map metadata here
+        return value;
+    }
+
+    @Override
+    public Map newMap(MemoryBuffer buffer) {
+        // Read map size
+        int numElements = buffer.readVarUint32Small7();
+        setNumElements(numElements);
+        // Create and return new map instance
+        T map = (T) new HashMap(numElements);
+        fory.getRefResolver().reference(map);
+        return map;
+    }
+}
+```
+
+Note that please invoke `setNumElements` when implementing `newMap` to let 
fory know how many elements to deserialize.
+
+#### Implement a totally-customzied Map Serializer without JIT
+
+Sometimes you may need complete control over the serialization process, or 
your map type might have special requirements that don't fit the standard 
patterns. In such cases, you can implement a serializer with 
`supportCodegenHook=false` and directly override the `write` and `read` methods.
+
+This approach:
+
+- Gives you full control over serialization
+- Allows custom binary format
+- Bypasses the standard map serialization pattern
+- May be simpler for special cases
+
+Here's an example:
+
+```java
+class FixedValueMap extends AbstractMap<String, Integer> {
+    private final Set<String> keys;
+    private final int fixedValue;
+
+    public FixedValueMap(Set<String> keys, int fixedValue) {
+        this.keys = keys;
+        this.fixedValue = fixedValue;
+    }
+
+    @Override
+    public Set<Entry<String, Integer>> entrySet() {
+        Set<Entry<String, Integer>> entries = new HashSet<>();
+        for (String key : keys) {
+            entries.add(new SimpleEntry<>(key, fixedValue));
+        }
+        return entries;
+    }
+
+    @Override
+    public Integer get(Object key) {
+        return keys.contains(key) ? fixedValue : null;
+    }
+
+    public Set<String> getKeys() {
+        return keys;
+    }
+
+    public int getFixedValue() {
+        return fixedValue;
+    }
+}
+
+class FixedValueMapSerializer extends AbstractMapSerializer<FixedValueMap> {
+    public FixedValueMapSerializer(Fory fory) {
+        // Disable codegen since we're handling serialization directly
+        super(fory, FixedValueMap.class, false);
+    }
+
+    @Override
+    public void write(MemoryBuffer buffer, FixedValueMap value) {
+        // Write the fixed value
+        buffer.writeInt32(value.getFixedValue());
+        // Write the number of keys
+        buffer.writeVarUint32Small7(value.getKeys().size());
+        // Write each key
+        for (String key : value.getKeys()) {
+            buffer.writeString(key);
+        }
+    }
+
+    @Override
+    public FixedValueMap read(MemoryBuffer buffer) {
+        // Read the fixed value
+        int fixedValue = buffer.readInt32();
+        // Read the number of keys
+        int size = buffer.readVarUint32Small7();
+        Set<String> keys = new HashSet<>(size);
+        for (int i = 0; i < size; i++) {
+            keys.add(buffer.readString());
+        }
+        return new FixedValueMap(keys, fixedValue);
+    }
+
+    // These methods are not used when supportCodegenHook is false
+    @Override
+    public Map onMapWrite(MemoryBuffer buffer, FixedValueMap value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FixedValueMap onMapRead(Map map) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FixedValueMap onMapCopy(Map map) {
+        throw new UnsupportedOperationException();
+    }
+}
+```
+
+Key Points:
+
+1. **Disable Codegen**:
+
+   - Set `supportCodegenHook=false` in constructor
+   - Fory will use your `write`/`read` methods directly
+   - No JIT optimization will be applied
+   - Full control over serialization format
+
+2. **Write Method**:
+
+   - Handle all serialization manually
+   - Write custom fields first
+   - Write map entries in your preferred format
+   - Control the exact binary layout
+
+3. **Read Method**:
+
+   - Handle all deserialization manually
+   - Read in same order as written
+   - Create and populate map instance
+   - Restore custom fields
+
+4. **Unused Methods**:
+   - `onMapWrite`, `onMapRead`, `onMapCopy` are not used
+   - Can throw `UnsupportedOperationException`
+   - Only `write` and `read` are important
+
+When to Use: this approach is best when
+
+- Map has custom fields or metadata
+- Special serialization format is needed
+- Complete control over binary format is required
+- Standard map patterns don't fit
+
+Trade-offs
+
+1. **Advantages**:
+
+   - Complete control over serialization
+   - Custom binary format possible
+   - Simpler implementation for special cases
+   - Direct handling of custom fields
+
+2. **Disadvantages**:
+   - No JIT optimization
+   - Potentially lower performance
+   - Manual handling of all serialization
+   - More code to maintain
+
+Remember that disabling codegen means giving up some performance optimizations 
that Fory provides. Only use this approach when the standard map serialization 
pattern doesn't meet your needs.
+
+#### Implement Serializer for Map-like Types
+
+Sometimes you may want to implement a serializer for a type that behaves like 
a map but isn't a standard Java map. This section demonstrates how to implement 
a serializer for such types.
+
+The key principles for map-like type serialization are:
+
+1. Extend `AbstractMapSerializer` for custom collection-like types
+2. Enable JIT optimization with `supportCodegenHook`
+3. Provide efficient element access through views
+4. Maintain proper size tracking
+
+Here's a complete example:
+
+```java
+// It's better to make it to implements the java.util.Map interface, in this 
way we don't have to implement such serializers by ourself.
+class CustomMapLike {
+    private final Object[] keyArray;
+    private final Object[] valueArray;
+    private final int size;
+
+    // Constructor for creating new instance
+    public CustomMapLike(int initialCapacity) {
+        this.keyArray = new Object[initialCapacity];
+        this.valueArray = new Object[initialCapacity];
+        this.size = 0;
+    }
+
+    // Constructor for wrapping existing arrays
+    public CustomMapLike(Object[] keyArray, Object[] valueArray, int size) {
+        this.keyArray = keyArray;
+        this.valueArray = valueArray;
+        this.size = size;
+    }
+
+    public Integer get(String key) {
+        for (int i = 0; i < size; i++) {
+            if (key.equals(keyArray[i])) {
+                return (Integer) valueArray[i];
+            }
+        }
+        return null;
+    }
+
+    public int size() {
+        return size;
+    }
+
+    public Object[] getKeyArray() {
+        return keyArray;
+    }
+
+    public Object[] getValueArray() {
+        return valueArray;
+    }
+}
+
+class MapView extends AbstractMap<Object, Object> {
+    private final Object[] keyArray;
+    private final Object[] valueArray;
+    private final int size;
+    private int writeIndex;
+
+    // Constructor for serialization (wrapping existing CustomMapLike)
+    public MapView(CustomMapLike mapLike) {
+        this.size = mapLike.size();
+        this.keyArray = mapLike.getKeyArray();
+        this.valueArray = mapLike.getValueArray();
+    }
+
+    // Constructor for deserialization
+    public MapView(int size) {
+        this.size = size;
+        this.keyArray = new Object[size];
+        this.valueArray = new Object[size];
+    }
+
+    @Override
+    public Set<Entry<Object, Object>> entrySet() {
+        return new AbstractSet<Entry<Object, Object>>() {
+            @Override
+            public Iterator<Entry<Object, Object>> iterator() {
+                return new Iterator<Entry<Object, Object>>() {
+                    private int index = 0;
+
+                    @Override
+                    public boolean hasNext() {
+                        return index < size;
+                    }
+
+                    @Override
+                    public Entry<Object, Object> next() {
+                        if (!hasNext()) {
+                            throw new NoSuchElementException();
+                        }
+                        final int currentIndex = index++;
+                        return new SimpleEntry<>(
+                            keyArray[currentIndex],
+                            valueArray[currentIndex]
+                        );
+                    }
+                };
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+        };
+    }
+
+    @Override
+    public Object put(Object key, Object value) {
+        if (writeIndex >= size) {
+            throw new IllegalStateException("Map is full");
+        }
+        keyArray[writeIndex] = key;
+        valueArray[writeIndex] = value;
+        writeIndex++;
+        return null;
+    }
+
+    public Object[] getKeyArray() {
+        return keyArray;
+    }
+
+    public Object[] getValueArray() {
+        return valueArray;
+    }
+
+    public int size() {
+        return size;
+    }
+}
+
+class CustomMapLikeSerializer extends AbstractMapSerializer<CustomMapLike> {
+    public CustomMapLikeSerializer(Fory fory) {
+        super(fory, CustomMapLike.class, true);
+    }
+
+    @Override
+    public Map onMapWrite(MemoryBuffer buffer, CustomMapLike value) {
+        buffer.writeVarUint32Small7(value.size());
+        // Return a zero-copy view using the same underlying arrays
+        return new MapView(value);
+    }
+
+    @Override
+    public Map newMap(MemoryBuffer buffer) {
+        int numElements = buffer.readVarUint32Small7();
+        setNumElements(numElements);
+        // Create a view with new arrays for deserialization
+        return new MapView(numElements);
+    }
+
+    @Override
+    public CustomMapLike onMapRead(Map map) {
+        MapView view = (MapView) map;
+        // Just pass the arrays directly - no copying needed
+        return new CustomMapLike(view.getKeyArray(), view.getValueArray(), 
view.size());
+    }
+
+    @Override
+    public CustomMapLike onMapCopy(Map map) {
+        MapView view = (MapView) map;
+        // Just pass the arrays directly - no copying needed
+        return new CustomMapLike(view.getKeyArray(), view.getValueArray(), 
view.size());
+    }
+}
+```
+
+### Register Custom Serializers
+
+After implementing your custom serializer, register it with Fory:
+
+```java
+Fory fory = Fory.builder()
+    .withLanguage(Language.JAVA)
+    .build();
+
+// Register map serializer
+fory.registerSerializer(CustomMap.class, new CustomMapSerializer<>(fory, 
CustomMap.class));
+
+// Register collection serializer
+fory.registerSerializer(CustomCollection.class, new 
CustomCollectionSerializer<>(fory, CustomCollection.class));
+```
+
+Note that when implementing custom map or collection serializers:
+
+1. Always extend the appropriate base class 
(`MapSerializer`/`AbstractMapSerializer` for maps, 
`CollectionSerializer`/`AbstractCollectionSerializer` for collections)
+2. Consider the impact of `supportCodegenHook` on performance and functionality
+3. Properly handle reference tracking if needed
+4. Implement proper size management using `setNumElements` and 
`getAndClearNumElements` when `supportCodegenHook` is `true`
+
 ### Security & Class Registration
 
 `ForyBuilder#requireClassRegistration` can be used to disable class 
registration, this will allow to deserialize objects
@@ -463,13 +1253,14 @@ returned.
 ### Coping/Mapping object from one type to another type
 
 Fory support mapping object from one type to another type.
+
 > Notes:
 >
 > 1. This mapping will execute a deep copy, all mapped fields are serialized 
 > into binary and
-     deserialized from that binary to map into another type.
+> deserialized from that binary to map into another type.
 > 2. All struct types must be registered with same ID, otherwise Fory can not 
 > mapping to correct struct type.
-     > Be careful when you use `Fory#register(Class)`, because fory will 
allocate an auto-grown ID which might be
-     > inconsistent if you register classes with different order between Fory 
instance.
+> Be careful when you use `Fory#register(Class)`, because fory will allocate 
an auto-grown ID which might be
+> inconsistent if you register classes with different order between Fory 
instance.
 
 ```java
 public class StructMappingExample {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to