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.git


The following commit(s) were added to refs/heads/main by this push:
     new d86dab5ee feat(java): separate user register type id with fory 
registered type id (#3035)
d86dab5ee is described below

commit d86dab5ee4c8381ca1d89ec5398e48507a5afd00
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Dec 10 18:25:26 2025 +0800

    feat(java): separate user register type id with fory registered type id 
(#3035)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    Closes #2609
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 docs/guide/java_serialization_guide.md             |   2 +-
 .../org/apache/fory/AbstractThreadSafeFory.java    |   5 -
 .../main/java/org/apache/fory/ThreadSafeFory.java  |   5 +
 .../org/apache/fory/resolver/ClassResolver.java    | 380 ++++++++++++++-------
 .../org/apache/fory/resolver/TypeResolver.java     |  34 ++
 .../apache/fory/serializer/ArraySerializers.java   |  45 +--
 .../fory/serializer/OptionalSerializers.java       |   8 +-
 .../fory/serializer/PrimitiveSerializers.java      |  32 +-
 .../org/apache/fory/serializer/Serializers.java    |  28 +-
 .../apache/fory/serializer/TimeSerializers.java    |  34 +-
 .../collection/CollectionSerializers.java          |  47 +--
 .../collection/GuavaCollectionSerializers.java     |  34 +-
 .../collection/ImmutableCollectionSerializers.java |  14 +-
 .../fory/serializer/collection/MapSerializers.java |  21 +-
 .../serializer/collection/SubListSerializers.java  |   5 +-
 .../collection/SynchronizedSerializers.java        |   2 +-
 .../collection/UnmodifiableSerializers.java        |   2 +-
 .../apache/fory/resolver/ClassResolverTest.java    |  33 +-
 .../serializer/CompressedArraySerializers.java     |  32 +-
 19 files changed, 495 insertions(+), 268 deletions(-)

diff --git a/docs/guide/java_serialization_guide.md 
b/docs/guide/java_serialization_guide.md
index 324f9f50d..6b7bef3f5 100644
--- a/docs/guide/java_serialization_guide.md
+++ b/docs/guide/java_serialization_guide.md
@@ -1441,7 +1441,7 @@ should have same registration order.
 ```java
 Fory fory = xxx;
 fory.register(SomeClass.class);
-fory.register(SomeClass1.class, 200);
+fory.register(SomeClass1.class, 1);
 ```
 
 If you invoke `ForyBuilder#requireClassRegistration(false)` to disable class 
registration check,
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java 
b/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
index a2aaf6e14..820b98a93 100644
--- a/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
@@ -19,9 +19,7 @@
 
 package org.apache.fory;
 
-import java.util.function.Consumer;
 import java.util.function.Function;
-import org.apache.fory.annotation.Internal;
 import org.apache.fory.resolver.ClassChecker;
 import org.apache.fory.resolver.TypeChecker;
 import org.apache.fory.serializer.Serializer;
@@ -113,7 +111,4 @@ public abstract class AbstractThreadSafeFory implements 
ThreadSafeFory {
           return null;
         });
   }
-
-  @Internal
-  public abstract void registerCallback(Consumer<Fory> callback);
 }
diff --git a/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java 
b/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
index 8c39f918e..16c8d8126 100644
--- a/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
@@ -20,7 +20,9 @@
 package org.apache.fory;
 
 import java.nio.ByteBuffer;
+import java.util.function.Consumer;
 import java.util.function.Function;
+import org.apache.fory.annotation.Internal;
 import org.apache.fory.resolver.ClassChecker;
 import org.apache.fory.resolver.TypeChecker;
 import org.apache.fory.serializer.SerializerFactory;
@@ -98,4 +100,7 @@ public interface ThreadSafeFory extends BaseFory {
    * @see LoaderBinding#clearClassLoader(ClassLoader)
    */
   void clearClassLoader(ClassLoader loader);
+
+  @Internal
+  void registerCallback(Consumer<Fory> callback);
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
index 9ca721200..fbc0a261c 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
@@ -158,16 +158,52 @@ import org.apache.fory.util.record.RecordUtils;
 /**
  * Class registry for types of serializing objects, responsible for 
reading/writing types, setting
  * up relations between serializer and types.
+ *
+ * <h2>Class ID Space</h2>
+ *
+ * <p>Fory separates user class IDs from internal class IDs to provide a clean 
and intuitive API:
+ *
+ * <ul>
+ *   <li><b>User ID space</b>: IDs specified via {@link #register(Class, int)} 
start from 0. Valid
+ *       range is [0, {@value Short#MAX_VALUE} - {@value #USER_ID_BASE} - 1] 
(i.e., [0, 32510]).
+ *   <li><b>Internal ID space</b>: Reserved for Fory's built-in types 
(primitives, common
+ *       collections, etc.). These IDs are in the range [0, {@value 
#USER_ID_BASE} - 1] and are
+ *       completely hidden from users.
+ * </ul>
+ *
+ * <p>When users register a class with ID N, Fory internally stores it as (N + 
{@value
+ * #USER_ID_BASE}). This transformation is transparent to users - they only 
work with their own
+ * 0-based ID space.
+ *
+ * <h2>Registration Methods</h2>
+ *
+ * <ul>
+ *   <li>{@link #register(Class)} - Auto-assigns the next available user ID
+ *   <li>{@link #register(Class, int)} - Registers with a user-specified ID 
(0-based)
+ *   <li>{@link #register(Class, String, String)} - Registers with namespace 
and type name
+ * </ul>
+ *
+ * @see #register(Class)
+ * @see #register(Class, int)
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class ClassResolver extends TypeResolver {
   private static final Logger LOG = 
LoggerFactory.getLogger(ClassResolver.class);
 
-  // preserve 0 as flag for class id not set in ClassInfo`
+  /** Flag value indicating no class ID has been assigned. */
   public static final short NO_CLASS_ID = TypeResolver.NO_CLASS_ID;
+
   public static final short LAMBDA_STUB_ID = 1;
   public static final short JDK_PROXY_STUB_ID = 2;
   public static final short REPLACE_STUB_ID = 3;
+
+  /**
+   * Base offset for user-registered class IDs. User IDs are internally stored 
as (userId + {@value
+   * #USER_ID_BASE}). The first {@value #USER_ID_BASE} IDs (0 to {@value 
#USER_ID_BASE} - 1) are
+   * reserved for Fory's internal types.
+   */
+  public static final short USER_ID_BASE = 256;
+
   // Note: following pre-defined class id should be continuous, since they may 
be used based range.
   public static final short PRIMITIVE_VOID_CLASS_ID = (short) (REPLACE_STUB_ID 
+ 1);
   public static final short PRIMITIVE_BOOLEAN_CLASS_ID = (short) 
(PRIMITIVE_VOID_CLASS_ID + 1);
@@ -228,43 +264,43 @@ public class ClassResolver extends TypeResolver {
   @Override
   public void initialize() {
     extRegistry.objectGenericType = buildGenericType(OBJECT_TYPE);
-    register(LambdaSerializer.ReplaceStub.class, LAMBDA_STUB_ID);
-    register(JdkProxySerializer.ReplaceStub.class, JDK_PROXY_STUB_ID);
-    register(ReplaceResolveSerializer.ReplaceStub.class, REPLACE_STUB_ID);
-    register(void.class, PRIMITIVE_VOID_CLASS_ID);
-    register(boolean.class, PRIMITIVE_BOOLEAN_CLASS_ID);
-    register(byte.class, PRIMITIVE_BYTE_CLASS_ID);
-    register(char.class, PRIMITIVE_CHAR_CLASS_ID);
-    register(short.class, PRIMITIVE_SHORT_CLASS_ID);
-    register(int.class, PRIMITIVE_INT_CLASS_ID);
-    register(float.class, PRIMITIVE_FLOAT_CLASS_ID);
-    register(long.class, PRIMITIVE_LONG_CLASS_ID);
-    register(double.class, PRIMITIVE_DOUBLE_CLASS_ID);
-    register(Void.class, VOID_CLASS_ID);
-    register(Boolean.class, BOOLEAN_CLASS_ID);
-    register(Byte.class, BYTE_CLASS_ID);
-    register(Character.class, CHAR_CLASS_ID);
-    register(Short.class, SHORT_CLASS_ID);
-    register(Integer.class, INTEGER_CLASS_ID);
-    register(Float.class, FLOAT_CLASS_ID);
-    register(Long.class, LONG_CLASS_ID);
-    register(Double.class, DOUBLE_CLASS_ID);
-    register(String.class, STRING_CLASS_ID);
-    register(boolean[].class, PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID);
-    register(byte[].class, PRIMITIVE_BYTE_ARRAY_CLASS_ID);
-    register(char[].class, PRIMITIVE_CHAR_ARRAY_CLASS_ID);
-    register(short[].class, PRIMITIVE_SHORT_ARRAY_CLASS_ID);
-    register(int[].class, PRIMITIVE_INT_ARRAY_CLASS_ID);
-    register(float[].class, PRIMITIVE_FLOAT_ARRAY_CLASS_ID);
-    register(long[].class, PRIMITIVE_LONG_ARRAY_CLASS_ID);
-    register(double[].class, PRIMITIVE_DOUBLE_ARRAY_CLASS_ID);
-    register(String[].class, STRING_ARRAY_CLASS_ID);
-    register(Object[].class, OBJECT_ARRAY_CLASS_ID);
-    register(ArrayList.class, ARRAYLIST_CLASS_ID);
-    register(HashMap.class, HASHMAP_CLASS_ID);
-    register(HashSet.class, HASHSET_CLASS_ID);
-    register(Class.class, CLASS_CLASS_ID);
-    register(Object.class, EMPTY_OBJECT_ID);
+    registerInternal(LambdaSerializer.ReplaceStub.class, LAMBDA_STUB_ID);
+    registerInternal(JdkProxySerializer.ReplaceStub.class, JDK_PROXY_STUB_ID);
+    registerInternal(ReplaceResolveSerializer.ReplaceStub.class, 
REPLACE_STUB_ID);
+    registerInternal(void.class, PRIMITIVE_VOID_CLASS_ID);
+    registerInternal(boolean.class, PRIMITIVE_BOOLEAN_CLASS_ID);
+    registerInternal(byte.class, PRIMITIVE_BYTE_CLASS_ID);
+    registerInternal(char.class, PRIMITIVE_CHAR_CLASS_ID);
+    registerInternal(short.class, PRIMITIVE_SHORT_CLASS_ID);
+    registerInternal(int.class, PRIMITIVE_INT_CLASS_ID);
+    registerInternal(float.class, PRIMITIVE_FLOAT_CLASS_ID);
+    registerInternal(long.class, PRIMITIVE_LONG_CLASS_ID);
+    registerInternal(double.class, PRIMITIVE_DOUBLE_CLASS_ID);
+    registerInternal(Void.class, VOID_CLASS_ID);
+    registerInternal(Boolean.class, BOOLEAN_CLASS_ID);
+    registerInternal(Byte.class, BYTE_CLASS_ID);
+    registerInternal(Character.class, CHAR_CLASS_ID);
+    registerInternal(Short.class, SHORT_CLASS_ID);
+    registerInternal(Integer.class, INTEGER_CLASS_ID);
+    registerInternal(Float.class, FLOAT_CLASS_ID);
+    registerInternal(Long.class, LONG_CLASS_ID);
+    registerInternal(Double.class, DOUBLE_CLASS_ID);
+    registerInternal(String.class, STRING_CLASS_ID);
+    registerInternal(boolean[].class, PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID);
+    registerInternal(byte[].class, PRIMITIVE_BYTE_ARRAY_CLASS_ID);
+    registerInternal(char[].class, PRIMITIVE_CHAR_ARRAY_CLASS_ID);
+    registerInternal(short[].class, PRIMITIVE_SHORT_ARRAY_CLASS_ID);
+    registerInternal(int[].class, PRIMITIVE_INT_ARRAY_CLASS_ID);
+    registerInternal(float[].class, PRIMITIVE_FLOAT_ARRAY_CLASS_ID);
+    registerInternal(long[].class, PRIMITIVE_LONG_ARRAY_CLASS_ID);
+    registerInternal(double[].class, PRIMITIVE_DOUBLE_ARRAY_CLASS_ID);
+    registerInternal(String[].class, STRING_ARRAY_CLASS_ID);
+    registerInternal(Object[].class, OBJECT_ARRAY_CLASS_ID);
+    registerInternal(ArrayList.class, ARRAYLIST_CLASS_ID);
+    registerInternal(HashMap.class, HASHMAP_CLASS_ID);
+    registerInternal(HashSet.class, HASHSET_CLASS_ID);
+    registerInternal(Class.class, CLASS_CLASS_ID);
+    registerInternal(Object.class, EMPTY_OBJECT_ID);
     registerCommonUsedClasses();
     registerDefaultClasses();
     addDefaultSerializers();
@@ -319,7 +355,7 @@ public class ClassResolver extends TypeResolver {
             
Objects.requireNonNull(classInfoMap.get(NonexistentMetaShared.class)).classId;
         Preconditions.checkArgument(classId > 63 && classId < 8192, classId);
       } else {
-        register(NonexistentSkip.class);
+        registerInternal(NonexistentSkip.class);
       }
     }
   }
@@ -329,122 +365,121 @@ public class ClassResolver extends TypeResolver {
   }
 
   private void addDefaultSerializer(Class type, Serializer serializer) {
-    registerSerializer(type, serializer);
-    register(type);
+    registerInternalSerializer(type, serializer);
+    registerInternal(type);
   }
 
   /** Register common class ahead to get smaller class id for serialization. */
   private void registerCommonUsedClasses() {
-    register(LinkedList.class, TreeSet.class);
-    register(LinkedHashMap.class, TreeMap.class);
-    register(Date.class, Timestamp.class, LocalDateTime.class, Instant.class);
-    register(BigInteger.class, BigDecimal.class);
-    register(Optional.class, OptionalInt.class);
-    register(Boolean[].class, Byte[].class, Short[].class, Character[].class);
-    register(Integer[].class, Float[].class, Long[].class, Double[].class);
+    registerInternal(LinkedList.class, TreeSet.class);
+    registerInternal(LinkedHashMap.class, TreeMap.class);
+    registerInternal(Date.class, Timestamp.class, LocalDateTime.class, 
Instant.class);
+    registerInternal(BigInteger.class, BigDecimal.class);
+    registerInternal(Optional.class, OptionalInt.class);
+    registerInternal(Boolean[].class, Byte[].class, Short[].class, 
Character[].class);
+    registerInternal(Integer[].class, Float[].class, Long[].class, 
Double[].class);
   }
 
   private void registerDefaultClasses() {
-    register(Platform.HEAP_BYTE_BUFFER_CLASS);
-    register(Platform.DIRECT_BYTE_BUFFER_CLASS);
-    register(Comparator.naturalOrder().getClass());
-    register(Comparator.reverseOrder().getClass());
-    register(ConcurrentHashMap.class);
-    register(ArrayBlockingQueue.class);
-    register(LinkedBlockingQueue.class);
-    register(AtomicBoolean.class);
-    register(AtomicInteger.class);
-    register(AtomicLong.class);
-    register(AtomicReference.class);
-    register(EnumSet.allOf(Language.class).getClass());
-    register(EnumSet.of(Language.JAVA).getClass());
-    register(SerializedLambda.class);
-    register(
+    registerInternal(Platform.HEAP_BYTE_BUFFER_CLASS);
+    registerInternal(Platform.DIRECT_BYTE_BUFFER_CLASS);
+    registerInternal(Comparator.naturalOrder().getClass());
+    registerInternal(Comparator.reverseOrder().getClass());
+    registerInternal(ConcurrentHashMap.class);
+    registerInternal(ArrayBlockingQueue.class);
+    registerInternal(LinkedBlockingQueue.class);
+    registerInternal(AtomicBoolean.class);
+    registerInternal(AtomicInteger.class);
+    registerInternal(AtomicLong.class);
+    registerInternal(AtomicReference.class);
+    registerInternal(EnumSet.allOf(Language.class).getClass());
+    registerInternal(EnumSet.of(Language.JAVA).getClass());
+    registerInternal(SerializedLambda.class);
+    registerInternal(
         Throwable.class,
         StackTraceElement.class,
         StackTraceElement[].class,
         Exception.class,
         RuntimeException.class);
-    register(NullPointerException.class);
-    register(IOException.class);
-    register(IllegalArgumentException.class);
-    register(IllegalStateException.class);
-    register(IndexOutOfBoundsException.class, 
ArrayIndexOutOfBoundsException.class);
+    registerInternal(NullPointerException.class);
+    registerInternal(IOException.class);
+    registerInternal(IllegalArgumentException.class);
+    registerInternal(IllegalStateException.class);
+    registerInternal(IndexOutOfBoundsException.class, 
ArrayIndexOutOfBoundsException.class);
   }
 
-  /** register class. */
+  /**
+   * Registers a class with an auto-assigned user ID.
+   *
+   * <p>The ID is automatically assigned starting from 0 in the user ID space. 
Each call assigns the
+   * next available ID. If the class is already registered, this method does 
nothing.
+   *
+   * <p>Example:
+   *
+   * <pre>{@code
+   * fory.register(MyClass.class);      // Gets user ID 0
+   * fory.register(AnotherClass.class); // Gets user ID 1
+   * }</pre>
+   *
+   * @param cls the class to register
+   */
+  @Override
   public void register(Class<?> cls) {
     if (!extRegistry.registeredClassIdMap.containsKey(cls)) {
-      while (extRegistry.classIdGenerator < registeredId2ClassInfo.length
-          && registeredId2ClassInfo[extRegistry.classIdGenerator] != null) {
-        extRegistry.classIdGenerator++;
+      while (extRegistry.userIdGenerator + USER_ID_BASE < 
registeredId2ClassInfo.length
+          && registeredId2ClassInfo[extRegistry.userIdGenerator + 
USER_ID_BASE] != null) {
+        extRegistry.userIdGenerator++;
       }
-      register(cls, extRegistry.classIdGenerator);
-    }
-  }
-
-  public void register(String className) {
-    register(loadClass(className, false, 0, false));
-  }
-
-  public void register(Class<?>... classes) {
-    for (Class<?> cls : classes) {
-      register(cls);
+      register(cls, extRegistry.userIdGenerator);
     }
   }
 
   /**
-   * This method has been deprecated, please use {@link #register(Class)} 
instead, and invoke {@link
-   * #ensureSerializersCompiled} after all classes has been registered.
+   * Registers a class by its fully qualified name with an auto-assigned user 
ID.
+   *
+   * @param className the fully qualified class name
+   * @see #register(Class)
    */
-  @Deprecated
-  public void register(Class<?> cls, boolean createSerializer) {
-    register(cls);
+  @Override
+  public void register(String className) {
+    register(loadClass(className, false, 0, false));
   }
 
   /**
-   * Register class with specified id. Currently class id must be `classId >= 
0 && classId < 32767`.
-   * In the future this limitation may be relaxed.
+   * Registers a class by its fully qualified name with a specified user ID.
+   *
+   * @param className the fully qualified class name
+   * @param classId the user ID to assign (0-based, in user ID space)
+   * @see #register(Class, int)
    */
-  public void register(Class<?> cls, int classId) {
-    checkRegisterAllowed();
-    // class id must be less than Integer.MAX_VALUE/2 since we use bit 0 as 
class id flag.
-    Preconditions.checkArgument(classId >= 0 && classId < Short.MAX_VALUE);
-    short id = (short) classId;
-    checkRegistration(cls, id, cls.getName());
-    extRegistry.registeredClassIdMap.put(cls, id);
-    if (registeredId2ClassInfo.length <= id) {
-      ClassInfo[] tmp = new ClassInfo[(id + 1) * 2];
-      System.arraycopy(registeredId2ClassInfo, 0, tmp, 0, 
registeredId2ClassInfo.length);
-      registeredId2ClassInfo = tmp;
-    }
-    ClassInfo classInfo = classInfoMap.get(cls);
-    if (classInfo != null) {
-      classInfo.classId = id;
-    } else {
-      classInfo = new ClassInfo(this, cls, null, id, NOT_SUPPORT_XLANG);
-      // make `extRegistry.registeredClassIdMap` and `classInfoMap` share same 
classInfo
-      // instances.
-      classInfoMap.put(cls, classInfo);
-    }
-    // serializer will be set lazily in `addSerializer` method if it's null.
-    registeredId2ClassInfo[id] = classInfo;
-    extRegistry.registeredClasses.put(cls.getName(), cls);
-    extRegistry.classIdGenerator++;
-    GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
-  }
-
+  @Override
   public void register(String className, int classId) {
     register(loadClass(className, false, 0, false), classId);
   }
 
   /**
-   * This method has been deprecated, please use {@link #register(Class, int)} 
instead, and invoke
-   * {@link #ensureSerializersCompiled} after all classes has been registered.
+   * Registers a class with a user-specified ID.
+   *
+   * <p>The ID is in the user ID space, starting from 0. Fory internally 
transforms this to an
+   * internal ID by adding {@link #USER_ID_BASE}. This separation ensures user 
IDs never conflict
+   * with Fory's internal type IDs.
+   *
+   * <p>Valid user ID range: [0, 32510] (i.e., [0, Short.MAX_VALUE - 
USER_ID_BASE - 1])
+   *
+   * <p>Example:
+   *
+   * <pre>{@code
+   * fory.register(MyClass.class, 0);      // User ID 0 -> Internal ID 256
+   * fory.register(AnotherClass.class, 1); // User ID 1 -> Internal ID 257
+   * }</pre>
+   *
+   * @param cls the class to register
+   * @param id the user ID to assign (0-based)
+   * @throws IllegalArgumentException if the ID is out of valid range or 
already in use
    */
-  @Deprecated
-  public void register(Class<?> cls, int id, boolean createSerializer) {
-    register(cls, id);
+  @Override
+  public void register(Class<?> cls, int id) {
+    registerImpl(cls, id + USER_ID_BASE);
   }
 
   /**
@@ -481,6 +516,83 @@ public class ClassResolver extends TypeResolver {
     GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
   }
 
+  /**
+   * Registers multiple classes for internal use with auto-assigned internal 
IDs.
+   *
+   * <p><b>Internal API</b>: This method is for Fory's internal use only. 
Users should use {@link
+   * #register(Class)} instead.
+   *
+   * @param classes the classes to register
+   */
+  public void registerInternal(Class<?>... classes) {
+    for (Class<?> cls : classes) {
+      registerInternal(cls);
+    }
+  }
+
+  /**
+   * Registers a class for internal use with an auto-assigned internal ID.
+   *
+   * <p><b>Internal API</b>: This method is for Fory's internal use only. 
Users should use {@link
+   * #register(Class)} instead. Internal IDs are in the range [0, {@link 
#USER_ID_BASE} - 1].
+   *
+   * @param cls the class to register
+   */
+  public void registerInternal(Class<?> cls) {
+    if (!extRegistry.registeredClassIdMap.containsKey(cls)) {
+      while (extRegistry.classIdGenerator < registeredId2ClassInfo.length
+          && registeredId2ClassInfo[extRegistry.classIdGenerator] != null) {
+        extRegistry.classIdGenerator++;
+      }
+      registerInternal(cls, extRegistry.classIdGenerator);
+    }
+  }
+
+  /**
+   * Registers a class for internal use with a specified internal ID.
+   *
+   * <p><b>Internal API</b>: This method is for Fory's internal use only. 
Users should use {@link
+   * #register(Class, int)} instead.
+   *
+   * <p>Internal IDs are reserved for Fory's built-in types and must be in the 
range [0, {@link
+   * #USER_ID_BASE} - 1] (i.e., [0, 255]). User IDs start from {@link 
#USER_ID_BASE} and above.
+   *
+   * @param cls the class to register
+   * @param classId the internal ID, must be in range [0, {@link 
#USER_ID_BASE} - 1]
+   * @throws IllegalArgumentException if the ID is out of range or already in 
use
+   */
+  public void registerInternal(Class<?> cls, int classId) {
+    Preconditions.checkArgument(classId >= 0 && classId < USER_ID_BASE);
+    registerImpl(cls, classId);
+  }
+
+  private void registerImpl(Class<?> cls, int classId) {
+    checkRegisterAllowed();
+    // class id must be less than Integer.MAX_VALUE/2 since we use bit 0 as 
class id flag.
+    Preconditions.checkArgument(classId >= 0 && classId < Short.MAX_VALUE);
+    short id = (short) classId;
+    checkRegistration(cls, id, cls.getName());
+    extRegistry.registeredClassIdMap.put(cls, id);
+    if (registeredId2ClassInfo.length <= id) {
+      ClassInfo[] tmp = new ClassInfo[(id + 1) * 2];
+      System.arraycopy(registeredId2ClassInfo, 0, tmp, 0, 
registeredId2ClassInfo.length);
+      registeredId2ClassInfo = tmp;
+    }
+    ClassInfo classInfo = classInfoMap.get(cls);
+    if (classInfo != null) {
+      classInfo.classId = id;
+    } else {
+      classInfo = new ClassInfo(this, cls, null, id, NOT_SUPPORT_XLANG);
+      // make `extRegistry.registeredClassIdMap` and `classInfoMap` share same 
classInfo
+      // instances.
+      classInfoMap.put(cls, classInfo);
+    }
+    // serializer will be set lazily in `addSerializer` method if it's null.
+    registeredId2ClassInfo[id] = classInfo;
+    extRegistry.registeredClasses.put(cls.getName(), cls);
+    GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
+  }
+
   private void checkRegistration(Class<?> cls, short classId, String name) {
     if (extRegistry.registeredClassIdMap.containsKey(cls)) {
       throw new IllegalArgumentException(
@@ -526,6 +638,7 @@ public class ClassResolver extends TypeResolver {
 
   public Tuple2<String, String> getRegisteredNameTuple(Class<?> cls) {
     String name = extRegistry.registeredClasses.inverse().get(cls);
+    Preconditions.checkNotNull(name);
     int index = name.lastIndexOf(".");
     if (index != -1) {
       return Tuple2.of(name.substring(0, index), name.substring(index + 1));
@@ -671,23 +784,38 @@ public class ClassResolver extends TypeResolver {
    * @param <T> type of class
    */
   public <T> void registerSerializer(Class<T> type, Class<? extends 
Serializer> serializerClass) {
-    checkRegisterAllowed();
     registerSerializer(type, Serializers.newSerializer(fory, type, 
serializerClass));
   }
 
+  @Override
+  public void registerSerializer(Class<?> type, Serializer<?> serializer) {
+    checkRegisterAllowed();
+    if 
(!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
+      SerializationUtils.validate(type, serializer.getClass());
+    }
+    if (!extRegistry.registeredClassIdMap.containsKey(type) && 
!fory.isCrossLanguage()) {
+      register(type);
+    }
+    registerSerializerImpl(type, serializer);
+  }
+
   /**
    * If a serializer exists before, it will be replaced by new serializer.
    *
    * @param type class needed to be serialized/deserialized
    * @param serializer serializer for object of {@code type}
    */
-  public void registerSerializer(Class<?> type, Serializer<?> serializer) {
+  public void registerInternalSerializer(Class<?> type, Serializer<?> 
serializer) {
+    registerSerializerImpl(type, serializer);
+  }
+
+  private void registerSerializerImpl(Class<?> type, Serializer<?> serializer) 
{
     checkRegisterAllowed();
     if 
(!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
       SerializationUtils.validate(type, serializer.getClass());
     }
     if (!extRegistry.registeredClassIdMap.containsKey(type) && 
!fory.isCrossLanguage()) {
-      register(type);
+      registerInternal(type);
     }
     addSerializer(type, serializer);
     ClassInfo classInfo = classInfoMap.get(type);
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
index 5b90c7b73..935ee2364 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
@@ -117,26 +117,59 @@ public abstract class TypeResolver {
     }
   }
 
+  /**
+   * Registers a class with an auto-assigned user ID.
+   *
+   * @param type the class to register
+   */
   public abstract void register(Class<?> type);
 
+  /**
+   * Registers a class with a user-specified ID. Valid ID range is [0, 32510].
+   *
+   * @param type the class to register
+   * @param id the user ID to assign (0-based)
+   */
   public abstract void register(Class<?> type, int id);
 
+  /**
+   * Registers a class with a namespace and type name for cross-language 
serialization.
+   *
+   * @param type the class to register
+   * @param namespace the namespace (can be empty if type name has no conflict)
+   * @param typeName the type name
+   */
   public abstract void register(Class<?> type, String namespace, String 
typeName);
 
+  /** Registers a class by name with an auto-assigned user ID. */
   public void register(String className) {
     register(loadClass(className));
   }
 
+  /** Registers a class by name with a user-specified ID. */
   public void register(String className, int classId) {
     register(loadClass(className), classId);
   }
 
+  /** Registers a class by name with a namespace and type name. */
   public void register(String className, String namespace, String typeName) {
     register(loadClass(className), namespace, typeName);
   }
 
+  /**
+   * Registers a custom serializer for a type.
+   *
+   * @param type the class to register
+   * @param serializer the serializer instance to use
+   */
   public abstract void registerSerializer(Class<?> type, Serializer<?> 
serializer);
 
+  /**
+   * Registers a custom serializer class for a type.
+   *
+   * @param type the class to register
+   * @param serializerClass the serializer class (will be instantiated by Fory)
+   */
   public abstract <T> void registerSerializer(
       Class<T> type, Class<? extends Serializer> serializerClass);
 
@@ -664,6 +697,7 @@ public abstract class TypeResolver {
     // Here we set it to 1 because `NO_CLASS_ID` is 0 to avoid calculating it 
again in
     // `register(Class<?> cls)`.
     short classIdGenerator = 1;
+    short userIdGenerator = 0;
     SerializerFactory serializerFactory;
     final IdentityMap<Class<?>, Short> registeredClassIdMap =
         new IdentityMap<>(estimatedNumRegistered);
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java 
b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
index 256207fbe..5042f8058 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
@@ -718,28 +718,35 @@ public class ArraySerializers {
 
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(Object[].class, new 
ObjectArraySerializer<>(fory, Object[].class));
-    resolver.registerSerializer(Class[].class, new 
ObjectArraySerializer<>(fory, Class[].class));
-    resolver.registerSerializer(byte[].class, new ByteArraySerializer(fory));
-    resolver.registerSerializer(Byte[].class, new 
ObjectArraySerializer<>(fory, Byte[].class));
-    resolver.registerSerializer(char[].class, new CharArraySerializer(fory));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
+        Object[].class, new ObjectArraySerializer<>(fory, Object[].class));
+    resolver.registerInternalSerializer(
+        Class[].class, new ObjectArraySerializer<>(fory, Class[].class));
+    resolver.registerInternalSerializer(byte[].class, new 
ByteArraySerializer(fory));
+    resolver.registerInternalSerializer(
+        Byte[].class, new ObjectArraySerializer<>(fory, Byte[].class));
+    resolver.registerInternalSerializer(char[].class, new 
CharArraySerializer(fory));
+    resolver.registerInternalSerializer(
         Character[].class, new ObjectArraySerializer<>(fory, 
Character[].class));
-    resolver.registerSerializer(short[].class, new ShortArraySerializer(fory));
-    resolver.registerSerializer(Short[].class, new 
ObjectArraySerializer<>(fory, Short[].class));
-    resolver.registerSerializer(int[].class, new IntArraySerializer(fory));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(short[].class, new 
ShortArraySerializer(fory));
+    resolver.registerInternalSerializer(
+        Short[].class, new ObjectArraySerializer<>(fory, Short[].class));
+    resolver.registerInternalSerializer(int[].class, new 
IntArraySerializer(fory));
+    resolver.registerInternalSerializer(
         Integer[].class, new ObjectArraySerializer<>(fory, Integer[].class));
-    resolver.registerSerializer(long[].class, new LongArraySerializer(fory));
-    resolver.registerSerializer(Long[].class, new 
ObjectArraySerializer<>(fory, Long[].class));
-    resolver.registerSerializer(float[].class, new FloatArraySerializer(fory));
-    resolver.registerSerializer(Float[].class, new 
ObjectArraySerializer<>(fory, Float[].class));
-    resolver.registerSerializer(double[].class, new 
DoubleArraySerializer(fory));
-    resolver.registerSerializer(Double[].class, new 
ObjectArraySerializer<>(fory, Double[].class));
-    resolver.registerSerializer(boolean[].class, new 
BooleanArraySerializer(fory));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(long[].class, new 
LongArraySerializer(fory));
+    resolver.registerInternalSerializer(
+        Long[].class, new ObjectArraySerializer<>(fory, Long[].class));
+    resolver.registerInternalSerializer(float[].class, new 
FloatArraySerializer(fory));
+    resolver.registerInternalSerializer(
+        Float[].class, new ObjectArraySerializer<>(fory, Float[].class));
+    resolver.registerInternalSerializer(double[].class, new 
DoubleArraySerializer(fory));
+    resolver.registerInternalSerializer(
+        Double[].class, new ObjectArraySerializer<>(fory, Double[].class));
+    resolver.registerInternalSerializer(boolean[].class, new 
BooleanArraySerializer(fory));
+    resolver.registerInternalSerializer(
         Boolean[].class, new ObjectArraySerializer<>(fory, Boolean[].class));
-    resolver.registerSerializer(String[].class, new 
StringArraySerializer(fory));
+    resolver.registerInternalSerializer(String[].class, new 
StringArraySerializer(fory));
   }
 
   // ########################## utils ##########################
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
index a1ccffb6d..a19fde5ef 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
@@ -132,9 +132,9 @@ public final class OptionalSerializers {
 
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(Optional.class, new OptionalSerializer(fory));
-    resolver.registerSerializer(OptionalInt.class, new 
OptionalIntSerializer(fory));
-    resolver.registerSerializer(OptionalLong.class, new 
OptionalLongSerializer(fory));
-    resolver.registerSerializer(OptionalDouble.class, new 
OptionalDoubleSerializer(fory));
+    resolver.registerInternalSerializer(Optional.class, new 
OptionalSerializer(fory));
+    resolver.registerInternalSerializer(OptionalInt.class, new 
OptionalIntSerializer(fory));
+    resolver.registerInternalSerializer(OptionalLong.class, new 
OptionalLongSerializer(fory));
+    resolver.registerInternalSerializer(OptionalDouble.class, new 
OptionalDoubleSerializer(fory));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
index 868ced0af..aecc0b56b 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
@@ -294,21 +294,21 @@ public class PrimitiveSerializers {
   public static void registerDefaultSerializers(Fory fory) {
     // primitive types will be boxed.
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(boolean.class, new BooleanSerializer(fory, 
boolean.class));
-    resolver.registerSerializer(byte.class, new ByteSerializer(fory, 
byte.class));
-    resolver.registerSerializer(short.class, new ShortSerializer(fory, 
short.class));
-    resolver.registerSerializer(char.class, new CharSerializer(fory, 
char.class));
-    resolver.registerSerializer(int.class, new IntSerializer(fory, int.class));
-    resolver.registerSerializer(long.class, new LongSerializer(fory, 
long.class));
-    resolver.registerSerializer(float.class, new FloatSerializer(fory, 
float.class));
-    resolver.registerSerializer(double.class, new DoubleSerializer(fory, 
double.class));
-    resolver.registerSerializer(Boolean.class, new BooleanSerializer(fory, 
Boolean.class));
-    resolver.registerSerializer(Byte.class, new ByteSerializer(fory, 
Byte.class));
-    resolver.registerSerializer(Short.class, new ShortSerializer(fory, 
Short.class));
-    resolver.registerSerializer(Character.class, new CharSerializer(fory, 
Character.class));
-    resolver.registerSerializer(Integer.class, new IntSerializer(fory, 
Integer.class));
-    resolver.registerSerializer(Long.class, new LongSerializer(fory, 
Long.class));
-    resolver.registerSerializer(Float.class, new FloatSerializer(fory, 
Float.class));
-    resolver.registerSerializer(Double.class, new DoubleSerializer(fory, 
Double.class));
+    resolver.registerInternalSerializer(boolean.class, new 
BooleanSerializer(fory, boolean.class));
+    resolver.registerInternalSerializer(byte.class, new ByteSerializer(fory, 
byte.class));
+    resolver.registerInternalSerializer(short.class, new ShortSerializer(fory, 
short.class));
+    resolver.registerInternalSerializer(char.class, new CharSerializer(fory, 
char.class));
+    resolver.registerInternalSerializer(int.class, new IntSerializer(fory, 
int.class));
+    resolver.registerInternalSerializer(long.class, new LongSerializer(fory, 
long.class));
+    resolver.registerInternalSerializer(float.class, new FloatSerializer(fory, 
float.class));
+    resolver.registerInternalSerializer(double.class, new 
DoubleSerializer(fory, double.class));
+    resolver.registerInternalSerializer(Boolean.class, new 
BooleanSerializer(fory, Boolean.class));
+    resolver.registerInternalSerializer(Byte.class, new ByteSerializer(fory, 
Byte.class));
+    resolver.registerInternalSerializer(Short.class, new ShortSerializer(fory, 
Short.class));
+    resolver.registerInternalSerializer(Character.class, new 
CharSerializer(fory, Character.class));
+    resolver.registerInternalSerializer(Integer.class, new IntSerializer(fory, 
Integer.class));
+    resolver.registerInternalSerializer(Long.class, new LongSerializer(fory, 
Long.class));
+    resolver.registerInternalSerializer(Float.class, new FloatSerializer(fory, 
Float.class));
+    resolver.registerInternalSerializer(Double.class, new 
DoubleSerializer(fory, Double.class));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java 
b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
index d1a46d7cb..a75da3ded 100644
--- a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
+++ b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
@@ -591,19 +591,19 @@ public class Serializers {
 
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(Class.class, new ClassSerializer(fory));
-    resolver.registerSerializer(StringBuilder.class, new 
StringBuilderSerializer(fory));
-    resolver.registerSerializer(StringBuffer.class, new 
StringBufferSerializer(fory));
-    resolver.registerSerializer(BigInteger.class, new 
BigIntegerSerializer(fory));
-    resolver.registerSerializer(BigDecimal.class, new 
BigDecimalSerializer(fory));
-    resolver.registerSerializer(AtomicBoolean.class, new 
AtomicBooleanSerializer(fory));
-    resolver.registerSerializer(AtomicInteger.class, new 
AtomicIntegerSerializer(fory));
-    resolver.registerSerializer(AtomicLong.class, new 
AtomicLongSerializer(fory));
-    resolver.registerSerializer(AtomicReference.class, new 
AtomicReferenceSerializer(fory));
-    resolver.registerSerializer(Currency.class, new CurrencySerializer(fory));
-    resolver.registerSerializer(URI.class, new URISerializer(fory));
-    resolver.registerSerializer(Pattern.class, new RegexSerializer(fory));
-    resolver.registerSerializer(UUID.class, new UUIDSerializer(fory));
-    resolver.registerSerializer(Object.class, new EmptyObjectSerializer(fory));
+    resolver.registerInternalSerializer(Class.class, new 
ClassSerializer(fory));
+    resolver.registerInternalSerializer(StringBuilder.class, new 
StringBuilderSerializer(fory));
+    resolver.registerInternalSerializer(StringBuffer.class, new 
StringBufferSerializer(fory));
+    resolver.registerInternalSerializer(BigInteger.class, new 
BigIntegerSerializer(fory));
+    resolver.registerInternalSerializer(BigDecimal.class, new 
BigDecimalSerializer(fory));
+    resolver.registerInternalSerializer(AtomicBoolean.class, new 
AtomicBooleanSerializer(fory));
+    resolver.registerInternalSerializer(AtomicInteger.class, new 
AtomicIntegerSerializer(fory));
+    resolver.registerInternalSerializer(AtomicLong.class, new 
AtomicLongSerializer(fory));
+    resolver.registerInternalSerializer(AtomicReference.class, new 
AtomicReferenceSerializer(fory));
+    resolver.registerInternalSerializer(Currency.class, new 
CurrencySerializer(fory));
+    resolver.registerInternalSerializer(URI.class, new URISerializer(fory));
+    resolver.registerInternalSerializer(Pattern.class, new 
RegexSerializer(fory));
+    resolver.registerInternalSerializer(UUID.class, new UUIDSerializer(fory));
+    resolver.registerInternalSerializer(Object.class, new 
EmptyObjectSerializer(fory));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java 
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
index f0b4d99ae..a328b65c5 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
@@ -709,22 +709,22 @@ public class TimeSerializers {
 
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(Date.class, new DateSerializer(fory));
-    resolver.registerSerializer(java.sql.Date.class, new 
SqlDateSerializer(fory));
-    resolver.registerSerializer(Time.class, new SqlTimeSerializer(fory));
-    resolver.registerSerializer(Timestamp.class, new 
TimestampSerializer(fory));
-    resolver.registerSerializer(LocalDate.class, new 
LocalDateSerializer(fory));
-    resolver.registerSerializer(LocalTime.class, new 
LocalTimeSerializer(fory));
-    resolver.registerSerializer(LocalDateTime.class, new 
LocalDateTimeSerializer(fory));
-    resolver.registerSerializer(Instant.class, new InstantSerializer(fory));
-    resolver.registerSerializer(Duration.class, new DurationSerializer(fory));
-    resolver.registerSerializer(ZoneOffset.class, new 
ZoneOffsetSerializer(fory));
-    resolver.registerSerializer(ZonedDateTime.class, new 
ZonedDateTimeSerializer(fory));
-    resolver.registerSerializer(Year.class, new YearSerializer(fory));
-    resolver.registerSerializer(YearMonth.class, new 
YearMonthSerializer(fory));
-    resolver.registerSerializer(MonthDay.class, new MonthDaySerializer(fory));
-    resolver.registerSerializer(Period.class, new PeriodSerializer(fory));
-    resolver.registerSerializer(OffsetTime.class, new 
OffsetTimeSerializer(fory));
-    resolver.registerSerializer(OffsetDateTime.class, new 
OffsetDateTimeSerializer(fory));
+    resolver.registerInternalSerializer(Date.class, new DateSerializer(fory));
+    resolver.registerInternalSerializer(java.sql.Date.class, new 
SqlDateSerializer(fory));
+    resolver.registerInternalSerializer(Time.class, new 
SqlTimeSerializer(fory));
+    resolver.registerInternalSerializer(Timestamp.class, new 
TimestampSerializer(fory));
+    resolver.registerInternalSerializer(LocalDate.class, new 
LocalDateSerializer(fory));
+    resolver.registerInternalSerializer(LocalTime.class, new 
LocalTimeSerializer(fory));
+    resolver.registerInternalSerializer(LocalDateTime.class, new 
LocalDateTimeSerializer(fory));
+    resolver.registerInternalSerializer(Instant.class, new 
InstantSerializer(fory));
+    resolver.registerInternalSerializer(Duration.class, new 
DurationSerializer(fory));
+    resolver.registerInternalSerializer(ZoneOffset.class, new 
ZoneOffsetSerializer(fory));
+    resolver.registerInternalSerializer(ZonedDateTime.class, new 
ZonedDateTimeSerializer(fory));
+    resolver.registerInternalSerializer(Year.class, new YearSerializer(fory));
+    resolver.registerInternalSerializer(YearMonth.class, new 
YearMonthSerializer(fory));
+    resolver.registerInternalSerializer(MonthDay.class, new 
MonthDaySerializer(fory));
+    resolver.registerInternalSerializer(Period.class, new 
PeriodSerializer(fory));
+    resolver.registerInternalSerializer(OffsetTime.class, new 
OffsetTimeSerializer(fory));
+    resolver.registerInternalSerializer(OffsetDateTime.class, new 
OffsetDateTimeSerializer(fory));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java
index 2aae03677..a7a7225bb 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java
@@ -1002,55 +1002,58 @@ public class CollectionSerializers {
 
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(ArrayList.class, new 
ArrayListSerializer(fory));
+    resolver.registerInternalSerializer(ArrayList.class, new 
ArrayListSerializer(fory));
     Class arrayAsListClass = Arrays.asList(1, 2).getClass();
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         arrayAsListClass, new ArraysAsListSerializer(fory, arrayAsListClass));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         LinkedList.class, new CollectionSerializer(fory, LinkedList.class, 
true));
-    resolver.registerSerializer(HashSet.class, new HashSetSerializer(fory));
-    resolver.registerSerializer(LinkedHashSet.class, new 
LinkedHashSetSerializer(fory));
-    resolver.registerSerializer(TreeSet.class, new SortedSetSerializer<>(fory, 
TreeSet.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(HashSet.class, new 
HashSetSerializer(fory));
+    resolver.registerInternalSerializer(LinkedHashSet.class, new 
LinkedHashSetSerializer(fory));
+    resolver.registerInternalSerializer(
+        TreeSet.class, new SortedSetSerializer<>(fory, TreeSet.class));
+    resolver.registerInternalSerializer(
         Collections.EMPTY_LIST.getClass(),
         new EmptyListSerializer(fory, (Class<List<?>>) 
Collections.EMPTY_LIST.getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.emptySortedSet().getClass(),
         new EmptySortedSetSerializer(
             fory, (Class<SortedSet<?>>) 
Collections.emptySortedSet().getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.EMPTY_SET.getClass(),
         new EmptySetSerializer(fory, (Class<Set<?>>) 
Collections.EMPTY_SET.getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.singletonList(null).getClass(),
         new CollectionsSingletonListSerializer(
             fory, (Class<List<?>>) 
Collections.singletonList(null).getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.singleton(null).getClass(),
         new CollectionsSingletonSetSerializer(
             fory, (Class<Set<?>>) Collections.singleton(null).getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         ConcurrentSkipListSet.class,
         new ConcurrentSkipListSetSerializer(fory, 
ConcurrentSkipListSet.class));
-    resolver.registerSerializer(Vector.class, new VectorSerializer(fory, 
Vector.class));
-    resolver.registerSerializer(ArrayDeque.class, new 
ArrayDequeSerializer(fory, ArrayDeque.class));
-    resolver.registerSerializer(BitSet.class, new BitSetSerializer(fory, 
BitSet.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(Vector.class, new 
VectorSerializer(fory, Vector.class));
+    resolver.registerInternalSerializer(
+        ArrayDeque.class, new ArrayDequeSerializer(fory, ArrayDeque.class));
+    resolver.registerInternalSerializer(BitSet.class, new 
BitSetSerializer(fory, BitSet.class));
+    resolver.registerInternalSerializer(
         PriorityQueue.class, new PriorityQueueSerializer(fory, 
PriorityQueue.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         ArrayBlockingQueue.class, new ArrayBlockingQueueSerializer(fory, 
ArrayBlockingQueue.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         LinkedBlockingQueue.class,
         new LinkedBlockingQueueSerializer(fory, LinkedBlockingQueue.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         CopyOnWriteArrayList.class,
         new CopyOnWriteArrayListSerializer(fory, CopyOnWriteArrayList.class));
     final Class setFromMapClass = Collections.newSetFromMap(new 
HashMap<>()).getClass();
-    resolver.registerSerializer(setFromMapClass, new 
SetFromMapSerializer(fory, setFromMapClass));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
+        setFromMapClass, new SetFromMapSerializer(fory, setFromMapClass));
+    resolver.registerInternalSerializer(
         ConcurrentHashMap.KeySetView.class,
         new ConcurrentHashMapKeySetViewSerializer(fory, 
ConcurrentHashMap.KeySetView.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         CopyOnWriteArraySet.class,
         new CopyOnWriteArraySetSerializer(fory, CopyOnWriteArraySet.class));
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
index 1b7ab42ad..535178886 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
@@ -404,63 +404,63 @@ public class GuavaCollectionSerializers {
     ClassResolver resolver = fory.getClassResolver();
     Class cls =
         loadClass(pkg + ".RegularImmutableBiMap", ImmutableBiMap.of("k1", 1, 
"k2", 4).getClass());
-    resolver.registerSerializer(cls, new ImmutableBiMapSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new 
ImmutableBiMapSerializer(fory, cls));
     cls = loadClass(pkg + ".SingletonImmutableBiMap", ImmutableBiMap.of(1, 
2).getClass());
-    resolver.registerSerializer(cls, new ImmutableBiMapSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new 
ImmutableBiMapSerializer(fory, cls));
     cls = loadClass(pkg + ".RegularImmutableMap", ImmutableMap.of("k1", 1, 
"k2", 2).getClass());
-    resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new ImmutableMapSerializer(fory, 
cls));
     cls = loadClass(pkg + ".RegularImmutableList", 
ImmutableList.of().getClass());
-    resolver.registerSerializer(cls, new RegularImmutableListSerializer(fory, 
cls));
+    resolver.registerInternalSerializer(cls, new 
RegularImmutableListSerializer(fory, cls));
     cls = loadClass(pkg + ".SingletonImmutableList", 
ImmutableList.of(1).getClass());
-    resolver.registerSerializer(cls, new ImmutableListSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new ImmutableListSerializer(fory, 
cls));
     cls = loadClass(pkg + ".RegularImmutableSet", ImmutableSet.of(1, 
2).getClass());
-    resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new ImmutableSetSerializer(fory, 
cls));
     cls = loadClass(pkg + ".SingletonImmutableSet", 
ImmutableSet.of(1).getClass());
-    resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+    resolver.registerInternalSerializer(cls, new ImmutableSetSerializer(fory, 
cls));
     // sorted set/map doesn't support xlang.
     cls = loadClass(pkg + ".RegularImmutableSortedSet", 
ImmutableSortedSet.of(1, 2).getClass());
-    resolver.registerSerializer(cls, new ImmutableSortedSetSerializer<>(fory, 
cls));
+    resolver.registerInternalSerializer(cls, new 
ImmutableSortedSetSerializer<>(fory, cls));
     cls = loadClass(pkg + ".ImmutableSortedMap", ImmutableSortedMap.of(1, 
2).getClass());
-    resolver.registerSerializer(cls, new ImmutableSortedMapSerializer<>(fory, 
cls));
+    resolver.registerInternalSerializer(cls, new 
ImmutableSortedMapSerializer<>(fory, cls));
 
     // Guava version before 19.0, of() return
     // 
EmptyImmutableSet/EmptyImmutableBiMap/EmptyImmutableSortedMap/EmptyImmutableSortedSet
     // we register if class exist or register empty to deserialize.
     if (checkClassExist(pkg + ".EmptyImmutableSet")) {
       cls = loadClass(pkg + ".EmptyImmutableSet", 
ImmutableSet.of().getClass());
-      resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSetSerializer(fory, cls));
     } else {
       class GuavaEmptySet {}
 
       cls = GuavaEmptySet.class;
-      resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSetSerializer(fory, cls));
     }
     if (checkClassExist(pkg + ".EmptyImmutableBiMap")) {
       cls = loadClass(pkg + ".EmptyImmutableBiMap", 
ImmutableBiMap.of().getClass());
-      resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableMapSerializer(fory, cls));
     } else {
       class GuavaEmptyBiMap {}
 
       cls = GuavaEmptyBiMap.class;
-      resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableMapSerializer(fory, cls));
     }
     if (checkClassExist(pkg + ".EmptyImmutableSortedSet")) {
       cls = loadClass(pkg + ".EmptyImmutableSortedSet", 
ImmutableSortedSet.of().getClass());
-      resolver.registerSerializer(cls, new ImmutableSortedSetSerializer(fory, 
cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSortedSetSerializer(fory, cls));
     } else {
       class GuavaEmptySortedSet {}
 
       cls = GuavaEmptySortedSet.class;
-      resolver.registerSerializer(cls, new ImmutableSortedSetSerializer(fory, 
cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSortedSetSerializer(fory, cls));
     }
     if (checkClassExist(pkg + ".EmptyImmutableSortedMap")) {
       cls = loadClass(pkg + ".EmptyImmutableSortedMap", 
ImmutableSortedMap.of().getClass());
-      resolver.registerSerializer(cls, new ImmutableSortedMapSerializer(fory, 
cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSortedMapSerializer(fory, cls));
     } else {
       class GuavaEmptySortedMap {}
 
       cls = GuavaEmptySortedMap.class;
-      resolver.registerSerializer(cls, new ImmutableSortedMapSerializer(fory, 
cls));
+      resolver.registerInternalSerializer(cls, new 
ImmutableSortedMapSerializer(fory, cls));
     }
   }
 
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
index 4664ea1e2..32e051cb3 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
@@ -261,12 +261,12 @@ public class ImmutableCollectionSerializers {
 
   public static void registerSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(List12, new ImmutableListSerializer(fory, 
List12));
-    resolver.registerSerializer(ListN, new ImmutableListSerializer(fory, 
ListN));
-    resolver.registerSerializer(SubList, new ImmutableListSerializer(fory, 
SubList));
-    resolver.registerSerializer(Set12, new ImmutableSetSerializer(fory, 
Set12));
-    resolver.registerSerializer(SetN, new ImmutableSetSerializer(fory, SetN));
-    resolver.registerSerializer(Map1, new ImmutableMapSerializer(fory, Map1));
-    resolver.registerSerializer(MapN, new ImmutableMapSerializer(fory, MapN));
+    resolver.registerInternalSerializer(List12, new 
ImmutableListSerializer(fory, List12));
+    resolver.registerInternalSerializer(ListN, new 
ImmutableListSerializer(fory, ListN));
+    resolver.registerInternalSerializer(SubList, new 
ImmutableListSerializer(fory, SubList));
+    resolver.registerInternalSerializer(Set12, new 
ImmutableSetSerializer(fory, Set12));
+    resolver.registerInternalSerializer(SetN, new ImmutableSetSerializer(fory, 
SetN));
+    resolver.registerInternalSerializer(Map1, new ImmutableMapSerializer(fory, 
Map1));
+    resolver.registerInternalSerializer(MapN, new ImmutableMapSerializer(fory, 
MapN));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java
index d61462239..1a05377dc 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java
@@ -495,27 +495,28 @@ public class MapSerializers {
   // TODO(chaokunyang) support ConcurrentSkipListMap.SubMap mo efficiently.
   public static void registerDefaultSerializers(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(HashMap.class, new HashMapSerializer(fory));
+    resolver.registerInternalSerializer(HashMap.class, new 
HashMapSerializer(fory));
     fory.getClassResolver()
-        .registerSerializer(LinkedHashMap.class, new 
LinkedHashMapSerializer(fory));
-    resolver.registerSerializer(TreeMap.class, new SortedMapSerializer<>(fory, 
TreeMap.class));
-    resolver.registerSerializer(
+        .registerInternalSerializer(LinkedHashMap.class, new 
LinkedHashMapSerializer(fory));
+    resolver.registerInternalSerializer(
+        TreeMap.class, new SortedMapSerializer<>(fory, TreeMap.class));
+    resolver.registerInternalSerializer(
         Collections.EMPTY_MAP.getClass(),
         new EmptyMapSerializer(fory, (Class<Map<?, ?>>) 
Collections.EMPTY_MAP.getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.emptySortedMap().getClass(),
         new EmptySortedMapSerializer(
             fory, (Class<SortedMap<?, ?>>) 
Collections.emptySortedMap().getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         Collections.singletonMap(null, null).getClass(),
         new SingletonMapSerializer(
             fory, (Class<Map<?, ?>>) Collections.singletonMap(null, 
null).getClass()));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         ConcurrentHashMap.class, new ConcurrentHashMapSerializer(fory, 
ConcurrentHashMap.class));
-    resolver.registerSerializer(
+    resolver.registerInternalSerializer(
         ConcurrentSkipListMap.class,
         new ConcurrentSkipListMapSerializer(fory, 
ConcurrentSkipListMap.class));
-    resolver.registerSerializer(EnumMap.class, new EnumMapSerializer(fory));
-    resolver.registerSerializer(LazyMap.class, new LazyMapSerializer(fory));
+    resolver.registerInternalSerializer(EnumMap.class, new 
EnumMapSerializer(fory));
+    resolver.registerInternalSerializer(LazyMap.class, new 
LazyMapSerializer(fory));
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
index 4cec75f4c..27da62670 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
@@ -70,9 +70,10 @@ public class SubListSerializers {
     for (Class<?> cls :
         new Class[] {SubListClass, RandomAccessSubListClass, 
ArrayListSubListClass}) {
       if (fory.trackingRef() && preserveView && !fory.isCrossLanguage()) {
-        classResolver.registerSerializer(cls, new SubListViewSerializer(fory, 
cls));
+        classResolver.registerInternalSerializer(cls, new 
SubListViewSerializer(fory, cls));
       } else {
-        classResolver.registerSerializer(cls, new SubListSerializer(fory, 
(Class<List>) cls));
+        classResolver.registerInternalSerializer(
+            cls, new SubListSerializer(fory, (Class<List>) cls));
       }
     }
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
index 782233bb1..9c8bf2c66 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
@@ -214,7 +214,7 @@ public class SynchronizedSerializers {
     try {
       ClassResolver resolver = fory.getClassResolver();
       for (Tuple2<Class<?>, Function> factory : synchronizedFactories()) {
-        resolver.registerSerializer(factory.f0, createSerializer(fory, 
factory));
+        resolver.registerInternalSerializer(factory.f0, createSerializer(fory, 
factory));
       }
     } catch (Throwable e) {
       ExceptionUtils.ignore(e);
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
index 5ef3ff33d..cc6797158 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
@@ -212,7 +212,7 @@ public class UnmodifiableSerializers {
     try {
       ClassResolver resolver = fory.getClassResolver();
       for (Tuple2<Class<?>, Function> factory : unmodifiableFactories()) {
-        resolver.registerSerializer(factory.f0, createSerializer(fory, 
factory));
+        resolver.registerInternalSerializer(factory.f0, createSerializer(fory, 
factory));
       }
     } catch (Throwable e) {
       ExceptionUtils.ignore(e);
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java 
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
index 34fcc589c..1328536e6 100644
--- 
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
+++ 
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
@@ -98,7 +98,7 @@ public class ClassResolverTest extends ForyTestBase {
     Assert.assertThrows(
         IllegalArgumentException.class, () -> classResolver.register(C1.class, 
"ns", "C1"));
     Assert.assertThrows(
-        IllegalArgumentException.class, () -> classResolver.register(C1.class, 
200));
+        IllegalArgumentException.class, () -> 
classResolver.registerInternal(C1.class, 200));
     classResolver.register(C2.class, "", "C2");
     classResolver.register(Foo.class, "ns", "Foo");
 
@@ -118,6 +118,35 @@ public class ClassResolverTest extends ForyTestBase {
     Fory fory = 
Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
   }
 
+  @Test
+  public void testRegisterClassWithUserIds() {
+    // Test that user IDs 0 and 1 work correctly (mapped to internal IDs 256 
and 257)
+    Fory fory = 
Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(true).build();
+    ClassResolver classResolver = fory.getClassResolver();
+
+    // Register with user ID 0
+    classResolver.register(Foo.class, 0);
+    // Register with user ID 1
+    classResolver.register(Bar.class, 1);
+
+    // Verify internal IDs are offset by USER_ID_BASE (256)
+    assertEquals(
+        classResolver.getRegisteredClassId(Foo.class).shortValue(), 
ClassResolver.USER_ID_BASE);
+    assertEquals(
+        classResolver.getRegisteredClassId(Bar.class).shortValue(),
+        (short) (ClassResolver.USER_ID_BASE + 1));
+
+    // Verify serialization/deserialization works
+    Foo foo = new Foo();
+    foo.f1 = 42;
+    serDeCheck(fory, foo);
+
+    Bar bar = new Bar();
+    bar.f1 = 10;
+    bar.f2 = 100L;
+    serDeCheck(fory, bar);
+  }
+
   @Test
   public void testGetSerializerClass() throws ClassNotFoundException {
     {
@@ -322,7 +351,7 @@ public class ClassResolverTest extends ForyTestBase {
       assertSame(classInfo.getSerializer().getClass(), ObjectSerializer.class);
     }
     {
-      classResolver.register(Bar.class);
+      classResolver.registerInternal(Bar.class);
       ClassInfo classInfo = classResolver.getClassInfo(Bar.class);
       classResolver.setSerializer(Bar.class, new ObjectSerializer<>(fory, 
Bar.class));
       Assert.assertSame(classResolver.getClassInfo(Bar.class), classInfo);
diff --git 
a/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
 
b/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
index e329afd00..7c7fe3edc 100644
--- 
a/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
+++ 
b/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
@@ -21,6 +21,7 @@ package org.apache.fory.serializer;
 
 import java.util.Arrays;
 import org.apache.fory.Fory;
+import org.apache.fory.ThreadSafeFory;
 import org.apache.fory.memory.MemoryBuffer;
 import org.apache.fory.memory.Platform;
 import org.apache.fory.resolver.ClassResolver;
@@ -73,13 +74,31 @@ public final class CompressedArraySerializers {
     boolean compressLong = fory.getConfig().compressLongArray();
 
     if (compressInt) {
-      resolver.registerSerializer(int[].class, new 
CompressedIntArraySerializer(fory));
+      resolver.registerInternalSerializer(int[].class, new 
CompressedIntArraySerializer(fory));
     }
     if (compressLong) {
-      resolver.registerSerializer(long[].class, new 
CompressedLongArraySerializer(fory));
+      resolver.registerInternalSerializer(long[].class, new 
CompressedLongArraySerializer(fory));
     }
   }
 
+  /**
+   * Register compressed array serializers with the given Fory instance.
+   *
+   * <p>Example usage:
+   *
+   * <pre>{@code
+   * ThreadSafeFory fory = Fory.builder()
+   *     .withConfig(Config.compressIntArray(true).compressLongArray(true))
+   *     .buildThreadSafeFory();
+   * CompressedArraySerializers.registerSerializers(fory);
+   * }</pre>
+   *
+   * @param fory the ThreadSafeFory instance to register serializers with
+   */
+  public static void registerIfEnabled(ThreadSafeFory fory) {
+    fory.registerCallback(CompressedArraySerializers::registerIfEnabled);
+  }
+
   /**
    * Register compressed array serializers with the given Fory instance.
    *
@@ -91,8 +110,13 @@ public final class CompressedArraySerializers {
    */
   public static void register(Fory fory) {
     ClassResolver resolver = fory.getClassResolver();
-    resolver.registerSerializer(int[].class, new 
CompressedIntArraySerializer(fory));
-    resolver.registerSerializer(long[].class, new 
CompressedLongArraySerializer(fory));
+    resolver.registerInternalSerializer(int[].class, new 
CompressedIntArraySerializer(fory));
+    resolver.registerInternalSerializer(long[].class, new 
CompressedLongArraySerializer(fory));
+  }
+
+  /** Register compressed array serializers with the given Fory instance. */
+  public static void register(ThreadSafeFory fory) {
+    fory.registerCallback(CompressedArraySerializers::register);
   }
 
   public static final class CompressedIntArraySerializer extends 
PrimitiveArraySerializer<int[]> {


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

Reply via email to