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 93e47c68c fix(java): fix meta share deserialization for register 
(#2667)
93e47c68c is described below

commit 93e47c68c81bf250a1718c9b0c763050dbfb516e
Author: Shawn Yang <[email protected]>
AuthorDate: Fri Sep 26 19:26:19 2025 +0800

    fix(java): fix meta share deserialization for register (#2667)
    
    ## Why?
    
    <!-- Describe the purpose of this PR. -->
    
    ## What does this PR do?
    
    1. fix meta share deserialization for register
    2. Add register by class name
    
    ## Related issues
    
    Fixes #2666
    
    Closes #2605
    
    ## Does this PR introduce any user-facing change?
    
    <!--
    If any user-facing interface changes, please [open an
    issue](https://github.com/apache/fory/issues/new/choose) describing the
    need to do so and update the document if necessary.
    
    Delete section if not applicable.
    -->
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    <!--
    When the PR has an impact on performance (if you don't know whether the
    PR will have an impact on performance, you can submit the PR first, and
    if it will have impact on performance, the code reviewer will explain
    it), be sure to attach a benchmark data here.
    
    Delete section if not applicable.
    -->
---
 docs/guide/graalvm_guide.md                        | 23 +++----
 .../java/org/apache/fory/graalvm/ArrayExample.java |  3 +-
 .../java/org/apache/fory/graalvm/Benchmark.java    | 10 +--
 .../org/apache/fory/graalvm/CompatibleExample.java |  3 +-
 .../fory/graalvm/CompatibleThreadSafeExample.java  |  3 +-
 .../main/java/org/apache/fory/graalvm/Example.java |  3 +-
 .../apache/fory/graalvm/ObjectStreamExample.java   |  2 +-
 .../java/org/apache/fory/graalvm/ProxyExample.java |  2 +-
 .../fory/graalvm/ScopedCompatibleExample.java      |  3 +-
 .../org/apache/fory/graalvm/ThreadSafeExample.java |  3 +-
 .../graalvm/record/CompatibleRecordExample.java    |  3 +-
 .../apache/fory/graalvm/record/RecordExample.java  |  3 +-
 .../apache/fory/graalvm/record/RecordExample2.java |  5 +-
 .../org/apache/fory/AbstractThreadSafeFory.java    | 16 +++++
 .../src/main/java/org/apache/fory/BaseFory.java    | 35 +++++++++--
 .../src/main/java/org/apache/fory/Fory.java        | 71 +++++++++-------------
 .../main/java/org/apache/fory/meta/ClassDef.java   | 25 ++++++--
 .../org/apache/fory/resolver/ClassResolver.java    | 56 +++++++++--------
 .../org/apache/fory/resolver/TypeResolver.java     | 36 +++++++++++
 .../org/apache/fory/resolver/XtypeResolver.java    |  3 +
 .../fory/serializer/ObjectStreamSerializer.java    |  4 ++
 .../org/apache/fory/serializer/RegisterTest.java   | 70 +++++++++++++++++++++
 22 files changed, 278 insertions(+), 104 deletions(-)

diff --git a/docs/guide/graalvm_guide.md b/docs/guide/graalvm_guide.md
index 6c5174fd9..88b005552 100644
--- a/docs/guide/graalvm_guide.md
+++ b/docs/guide/graalvm_guide.md
@@ -42,7 +42,7 @@ Args = 
--initialize-at-build-time=org.apache.fory.graalvm.Example
 
 Fory achieves this by using **codegen instead of reflection** - all 
serialization code is generated at build time when you call:
 
-- `fory.register(YourClass.class, true)` to register your classes
+- `fory.register(YourClass.class)` to register your classes
 - `fory.ensureSerializersCompiled()` to compile serializers at build time
 
 Note that Fory `asyncCompilationEnabled` option will be disabled automatically 
for graalvm native image since graalvm
@@ -61,8 +61,10 @@ This means you need to register your class with Fory. **Do 
NOT add it to reflect
 ```java
 static {
   fory = Fory.builder().build();
-  fory.register(MyClass.class, true);  // Enable codegen for this class
-  fory.ensureSerializersCompiled();    // Compile at build time
+  // register class
+  fory.register(MyClass.class);
+  // ensure all serializers for registered classes being compiled by fory at 
graalvm native image build time.
+  fory.ensureSerializersCompiled();
 }
 ```
 
@@ -97,9 +99,9 @@ public class Example {
 
   static {
     fory = Fory.builder().build();
-    // register and generate serializer code.
-    fory.register(Record.class, true);
-    // ensure lazy initialized serializers being compiled by fory.
+    // register class
+    fory.register(Record.class);
+    // ensure all serializers for registered classes being compiled by fory at 
graalvm native image build time.
     fory.ensureSerializersCompiled();
   }
 
@@ -144,9 +146,9 @@ public class ThreadSafeExample {
   static {
     fory = new ThreadLocalFory(classLoader -> {
       Fory f = Fory.builder().build();
-      // register and generate serializer code.
-      f.register(Foo.class, true);
-      // ensure lazy initialized serializers being compiled by fory.
+      // register class
+      f.register(Foo.class);
+      // ensure all serializers for registered classes being compiled by fory 
at graalvm native image build time.
       fory.ensureSerializersCompiled();
       return f;
     });
@@ -175,8 +177,7 @@ Args = 
--initialize-at-build-time=org.apache.fory.graalvm.ThreadSafeExample
 
 For framework developers, if you want to integrate fory for serialization, you 
can provided a configuration file to let
 the users to list all the classes they want to serialize, then you can load 
those classes and invoke
-`org.apache.fory.Fory.register(Class<?>, boolean)` to register those classes 
in your Fory integration class, and configure that
-class be initialized at graalvm native image build time.
+`org.apache.fory.Fory.register(Class<?>)` to register those classes in your 
Fory integration class. After all classes are registered, you need to invoke 
`org.apache.fory.Fory.ensureSerializersCompiled()` to compile serializers at 
build time, and configure that class be initialized at graalvm native image 
build time.
 
 ## Benchmark
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
index e002a5444..0d9da0861 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
@@ -28,7 +28,8 @@ public class ArrayExample {
   private static final Fory FORY = 
Fory.builder().registerGuavaTypes(false).build();
 
   static {
-    FORY.register(ArrayExample.class, true);
+    FORY.register(ArrayExample.class);
+    FORY.ensureSerializersCompiled();
   }
 
   byte[] bytes;
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
index f27b1c91e..832f41b6b 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
@@ -74,11 +74,13 @@ public class Benchmark {
 
   static {
     fory1 = Fory.builder().withNumberCompressed(false).build();
-    fory1.register(Foo.class, true);
-    fory1.register(Struct.class, true);
+    fory1.register(Foo.class);
+    fory1.register(Struct.class);
+    fory1.ensureSerializersCompiled();
     fory2 = Fory.builder().withNumberCompressed(true).build();
-    fory2.register(Foo.class, true);
-    fory2.register(Struct.class, true);
+    fory2.register(Foo.class);
+    fory2.register(Struct.class);
+    fory2.ensureSerializersCompiled();
   }
 
   public static void main(String[] args) {
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
index 634b3e178..d5e40a854 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
@@ -37,7 +37,8 @@ public class CompatibleExample {
             .withScopedMetaShare(false)
             .build();
     // register and generate serializer code.
-    fory.register(Foo.class, true);
+    fory.register(Foo.class);
+    fory.ensureSerializersCompiled();
     return fory;
   }
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
index a1a3fccc7..a63fbb4c4 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
@@ -38,7 +38,8 @@ public class CompatibleThreadSafeExample {
                       .withCompatibleMode(CompatibleMode.COMPATIBLE)
                       .build();
               // register and generate serializer code.
-              f.register(Foo.class, true);
+              f.register(Foo.class);
+              f.ensureSerializersCompiled();
               return f;
             });
     System.out.println("Init fory at build time");
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
index 86d357b7c..ee20eb123 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
@@ -30,7 +30,8 @@ public class Example {
   static {
     fory = 
Fory.builder().withName(Example.class.getName()).requireClassRegistration(true).build();
     // register and generate serializer code.
-    fory.register(Foo.class, true);
+    fory.register(Foo.class);
+    fory.ensureSerializersCompiled();
   }
 
   static void test(Fory fory) {
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
index 227ce126d..01a25ac79 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
@@ -33,7 +33,7 @@ public class ObjectStreamExample extends AbstractMap<Integer, 
Integer> {
           .build();
 
   static {
-    FORY.register(ObjectStreamExample.class, true);
+    FORY.register(ObjectStreamExample.class);
     FORY.ensureSerializersCompiled();
   }
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
index 2fd195675..525efa95d 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
@@ -49,7 +49,7 @@ public class ProxyExample {
             .requireClassRegistration(true)
             .build();
     // register and generate serializer code.
-    fory.register(TestInvocationHandler.class, true);
+    fory.register(TestInvocationHandler.class);
     fory.ensureSerializersCompiled();
     return fory;
   }
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
index 903931622..674e1b11e 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
@@ -38,7 +38,8 @@ public class ScopedCompatibleExample {
             .withScopedMetaShare(true)
             .build();
     // register and generate serializer code.
-    fory.register(Foo.class, true);
+    fory.register(Foo.class);
+    fory.ensureSerializersCompiled();
     return fory;
   }
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
index dfd5cb74d..dd45c3f29 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
@@ -43,7 +43,8 @@ public class ThreadSafeExample {
                       .requireClassRegistration(true)
                       .build();
               // register and generate serializer code.
-              f.register(Foo.class, true);
+              f.register(Foo.class);
+              f.ensureSerializersCompiled();
               return f;
             });
     System.out.println("Init fory at build time");
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
index 5e99cf09c..938aaf12c 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
@@ -37,7 +37,8 @@ public class CompatibleRecordExample {
             .withCompatibleMode(CompatibleMode.COMPATIBLE)
             .build();
     // register and generate serializer code.
-    fory.register(RecordExample.Record.class, true);
+    fory.register(RecordExample.Record.class);
+    fory.ensureSerializersCompiled();
     return fory;
   }
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
index 875154da3..16946f59f 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
@@ -40,7 +40,8 @@ public class RecordExample {
             .requireClassRegistration(true)
             .build();
     // register and generate serializer code.
-    fory.register(Record.class, true);
+    fory.register(Record.class);
+    fory.ensureSerializersCompiled();
     return fory;
   }
 
diff --git 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
index 2e464228b..7811b06f2 100644
--- 
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
+++ 
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
@@ -40,8 +40,9 @@ public class RecordExample2 {
             .requireClassRegistration(true)
             .build();
     // register and generate serializer code.
-    fory.register(Record.class, true);
-    fory.register(Foo.class, true);
+    fory.register(Record.class);
+    fory.register(Foo.class);
+    fory.ensureSerializersCompiled();
     return fory;
   }
 
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 9e1f31118..a2aaf6e14 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
@@ -48,6 +48,7 @@ public abstract class AbstractThreadSafeFory implements 
ThreadSafeFory {
     registerCallback(fory -> fory.register(cls, id, createSerializer));
   }
 
+  @Deprecated
   @Override
   public void register(Class<?> cls, String typeName) {
     registerCallback(fory -> fory.register(cls, typeName));
@@ -58,6 +59,21 @@ public abstract class AbstractThreadSafeFory implements 
ThreadSafeFory {
     registerCallback(fory -> fory.register(cls, namespace, typeName));
   }
 
+  @Override
+  public void register(String className) {
+    registerCallback(fory -> fory.register(className));
+  }
+
+  @Override
+  public void register(String className, int id) {
+    registerCallback(fory -> fory.register(className, id));
+  }
+
+  @Override
+  public void register(String className, String namespace, String typeName) {
+    registerCallback(fory -> fory.register(className, namespace, typeName));
+  }
+
   @Override
   public <T> void registerSerializer(Class<T> type, Class<? extends 
Serializer> serializerClass) {
     registerCallback(fory -> fory.registerSerializer(type, serializerClass));
diff --git a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java 
b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
index ff0b68c71..8d6b3c103 100644
--- a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
@@ -56,24 +56,46 @@ public interface BaseFory {
   void register(Class<?> cls, boolean createSerializer);
 
   /**
-   * Register class with specified id.
+   * Register class with specified id. This method has been deprecated, please 
use {@link
+   * #register(Class, int)} instead, and invoke {@link 
#ensureSerializersCompiled} after all classes
+   * has been registered.
    *
    * @param cls class to register.
    * @param id id for provided class.
    * @param createSerializer whether to create serializer, if true and codegen 
enabled, this will
-   *     generate the serializer code too.
+   *     generate the serializer code too. this parameter has no effect 
anymore on whether to
+   *     generate code, please use {@link #ensureSerializersCompiled} to 
trigger code generation
    */
+  @Deprecated
   void register(Class<?> cls, int id, boolean createSerializer);
 
   /** register class with given type name which will be used for 
cross-language serialization. */
   void register(Class<?> cls, String typeName);
 
   /**
-   * register class with given type namespace and name which will be used for 
cross-language
-   * serialization.
+   * register class with given type namespace and name. This can be used 
mapping different classes
+   * into same type when deserializing.
    */
   void register(Class<?> cls, String namespace, String typeName);
 
+  /**
+   * Register class and allocate an auto-grown ID for this class. Note that 
the registration order
+   * is important. If registration order is inconsistent, the allocated ID 
will be different, and
+   * the deserialization will failed.
+   *
+   * @param className full class name to register.
+   */
+  void register(String className);
+
+  /** register class with given id. */
+  void register(String className, int classId);
+
+  /**
+   * register class with given type namespace and name. This can be used 
mapping different classes
+   * into same type when deserializing.
+   */
+  void register(String className, String namespace, String typeName);
+
   /**
    * Register a Serializer for a class, and allocate an auto-grown ID for this 
class if it's not
    * registered yet. Note that the registration order is important. If 
registration order is
@@ -109,8 +131,11 @@ public interface BaseFory {
    * Ensure all compilation for serializers and accessors even for lazy 
initialized serializers.
    * This method will block until all compilation is done.
    *
-   * <p>This method is mainly used for graalvm native image build time and 
trigger compilation ahead
+   * <p>This method is mainly used for graalvm native image build time or 
trigger compilation ahead
    * for online service ahead to avoid cold start.
+   *
+   * <p>Note that this method should be invoked after all registrations and 
invoked only once.
+   * Repeated invocations will have no effect.
    */
   void ensureSerializersCompiled();
 
diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java 
b/java/fory-core/src/main/java/org/apache/fory/Fory.java
index 7b6c02920..9ec188021 100644
--- a/java/fory-core/src/main/java/org/apache/fory/Fory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java
@@ -176,41 +176,31 @@ public final class Fory implements BaseFory {
 
   @Override
   public void register(Class<?> cls) {
-    if (!crossLanguage) {
-      classResolver.register(cls);
-    } else {
-      xtypeResolver.register(cls);
-    }
+    _getTypeResolver().register(cls);
   }
 
   @Override
   public void register(Class<?> cls, int id) {
-    if (!crossLanguage) {
-      classResolver.register(cls, id);
-    } else {
-      xtypeResolver.register(cls, id);
-    }
+    _getTypeResolver().register(cls, id);
   }
 
+  @Deprecated
   @Override
   public void register(Class<?> cls, boolean createSerializer) {
-    if (!crossLanguage) {
-      classResolver.register(cls, createSerializer);
-    } else {
-      xtypeResolver.register(cls);
-    }
+    _getTypeResolver().register(cls);
   }
 
+  @Deprecated
   @Override
   public void register(Class<?> cls, int id, boolean createSerializer) {
-    if (!crossLanguage) {
-      classResolver.register(cls, id, createSerializer);
-    } else {
-      xtypeResolver.register(cls, id);
-    }
+    _getTypeResolver().register(cls, id);
   }
 
-  /** register class with given type tag which will be used for cross-language 
serialization. */
+  /**
+   * Register class with given type name, this method will have bigger 
serialization time/space cost
+   * compared to register by id.
+   */
+  @Override
   public void register(Class<?> cls, String typeName) {
     int idx = typeName.lastIndexOf('.');
     String namespace = "";
@@ -222,38 +212,37 @@ public final class Fory implements BaseFory {
   }
 
   public void register(Class<?> cls, String namespace, String typeName) {
-    if (!crossLanguage) {
-      classResolver.register(cls, namespace, typeName);
-    } else {
-      xtypeResolver.register(cls, namespace, typeName);
-    }
+    _getTypeResolver().register(cls, namespace, typeName);
+  }
+
+  @Override
+  public void register(String className) {
+    _getTypeResolver().register(className);
+  }
+
+  @Override
+  public void register(String className, int classId) {
+    _getTypeResolver().register(className, classId);
+  }
+
+  @Override
+  public void register(String className, String namespace, String typeName) {
+    _getTypeResolver().register(className, namespace, typeName);
   }
 
   @Override
   public <T> void registerSerializer(Class<T> type, Class<? extends 
Serializer> serializerClass) {
-    if (!crossLanguage) {
-      classResolver.registerSerializer(type, serializerClass);
-    } else {
-      xtypeResolver.registerSerializer(type, serializerClass);
-    }
+    _getTypeResolver().registerSerializer(type, serializerClass);
   }
 
   @Override
   public void registerSerializer(Class<?> type, Serializer<?> serializer) {
-    if (!crossLanguage) {
-      classResolver.registerSerializer(type, serializer);
-    } else {
-      xtypeResolver.registerSerializer(type, serializer);
-    }
+    _getTypeResolver().registerSerializer(type, serializer);
   }
 
   @Override
   public void registerSerializer(Class<?> type, Function<Fory, Serializer<?>> 
serializerCreator) {
-    if (!crossLanguage) {
-      classResolver.registerSerializer(type, serializerCreator.apply(this));
-    } else {
-      xtypeResolver.registerSerializer(type, serializerCreator.apply(this));
-    }
+    _getTypeResolver().registerSerializer(type, serializerCreator.apply(this));
   }
 
   @Override
diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java 
b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
index a8c0f0294..826b10e81 100644
--- a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
+++ b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
@@ -23,7 +23,6 @@ import static 
org.apache.fory.meta.ClassDefEncoder.buildFields;
 import static org.apache.fory.type.TypeUtils.COLLECTION_TYPE;
 import static org.apache.fory.type.TypeUtils.MAP_TYPE;
 import static org.apache.fory.type.TypeUtils.collectionOf;
-import static org.apache.fory.type.TypeUtils.getArrayComponent;
 import static org.apache.fory.type.TypeUtils.mapOf;
 
 import java.io.ObjectStreamClass;
@@ -270,11 +269,7 @@ public class ClassDef implements Serializable {
         if (descriptor != null) {
           // Make DescriptorGrouper have consistent order whether field exist 
or not
           // fory builtin types skip
-          if (rawType.isEnum()
-              || rawType.isAssignableFrom(descriptor.getRawType())
-              || NonexistentClass.isNonexistent(rawType)
-              || rawType == FinalObjectTypeStub.class
-              || (rawType.isArray() && getArrayComponent(rawType) == 
FinalObjectTypeStub.class)) {
+          if (useFieldType(rawType, descriptor)) {
             descriptor = descriptor.copyWithTypeName(newDesc.getTypeName());
             descriptors.add(descriptor);
           } else {
@@ -293,6 +288,24 @@ public class ClassDef implements Serializable {
     return descriptors;
   }
 
+  /** Returns true if can use current field type. */
+  private static boolean useFieldType(Class<?> parsedType, Descriptor 
descriptor) {
+    if (parsedType.isEnum()
+        || parsedType.isAssignableFrom(descriptor.getRawType())
+        || parsedType == FinalObjectTypeStub.class) {
+      return true;
+    }
+    if (parsedType.isArray()) {
+      Tuple2<Class<?>, Integer> info = 
TypeUtils.getArrayComponentInfo(parsedType);
+      Field field = descriptor.getField();
+      if (!field.getType().isArray() || 
TypeUtils.getArrayDimensions(field.getType()) != info.f1) {
+        return false;
+      }
+      return info.f0 == FinalObjectTypeStub.class || info.f0.isEnum();
+    }
+    return false;
+  }
+
   /**
    * FieldInfo contains all necessary info of a field to execute 
serialization/deserialization
    * logic.
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 ca11984f1..453f4de3a 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
@@ -360,7 +360,12 @@ public class ClassResolver extends TypeResolver {
     register(EnumSet.allOf(Language.class).getClass());
     register(EnumSet.of(Language.JAVA).getClass());
     register(SerializedLambda.class);
-    register(Throwable.class, StackTraceElement.class, Exception.class, 
RuntimeException.class);
+    register(
+        Throwable.class,
+        StackTraceElement.class,
+        StackTraceElement[].class,
+        Exception.class,
+        RuntimeException.class);
     register(NullPointerException.class);
     register(IOException.class);
     register(IllegalArgumentException.class);
@@ -389,11 +394,13 @@ public class ClassResolver extends TypeResolver {
     }
   }
 
+  /**
+   * This method has been deprecated, please use {@link #register(Class)} 
instead, and invoke {@link
+   * #ensureSerializersCompiled} after all classes has been registered.
+   */
+  @Deprecated
   public void register(Class<?> cls, boolean createSerializer) {
     register(cls);
-    if (createSerializer) {
-      createSerializerAhead(cls);
-    }
   }
 
   /**
@@ -430,15 +437,13 @@ public class ClassResolver extends TypeResolver {
     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.
+   */
+  @Deprecated
   public void register(Class<?> cls, int id, boolean createSerializer) {
     register(cls, id);
-    if (createSerializer) {
-      createSerializerAhead(cls);
-    }
-  }
-
-  public void register(String className, Short classId, boolean 
createSerializer) {
-    register(loadClass(className, false, 0, false), classId, createSerializer);
   }
 
   /**
@@ -446,6 +451,7 @@ public class ClassResolver extends TypeResolver {
    * registered, the serialized class will have smaller payload size. In many 
cases, it type name
    * has no conflict, namespace can be left as empty.
    */
+  @Override
   public void register(Class<?> cls, String namespace, String name) {
     Preconditions.checkArgument(!Functions.isLambda(cls));
     Preconditions.checkArgument(!ReflectionUtils.isJdkProxy(cls));
@@ -1236,7 +1242,7 @@ public class ClassResolver extends TypeResolver {
     if (!extRegistry.absClassInfo.isEmpty()) {
       Class<?> tmpCls = cls;
       while (tmpCls != null && tmpCls != Object.class) {
-        ClassInfo absClass = null;
+        ClassInfo absClass;
         if ((absClass = extRegistry.absClassInfo.get(tmpCls.getSuperclass())) 
!= null) {
           return absClass.serializer;
         }
@@ -1257,15 +1263,6 @@ public class ClassResolver extends TypeResolver {
     return serializer;
   }
 
-  private void createSerializerAhead(Class<?> cls) {
-    try {
-      fory.getJITContext().lock();
-      createSerializer0(cls);
-    } finally {
-      fory.getJITContext().unlock();
-    }
-  }
-
   private void createSerializer0(Class<?> cls) {
     ClassInfo classInfo = getClassInfo(cls);
     ClassInfo deserializationClassInfo;
@@ -1280,8 +1277,6 @@ public class ClassResolver extends TypeResolver {
             .deserializerClassMap
             .put(classDef.getId(), 
getGraalvmSerializerClass(deserializationClassInfo.serializer));
         Tuple2<ClassDef, ClassInfo> classDefTuple = 
extRegistry.classIdToDef.get(classDef.getId());
-        // empty serializer for graalvm build time
-        classDefTuple.f1.serializer = null;
         classInfoCache = NIL_CLASS_INFO;
         extRegistry.classIdToDef.put(classDef.getId(), 
Tuple2.of(classDefTuple.f0, null));
       }
@@ -1291,7 +1286,6 @@ public class ClassResolver extends TypeResolver {
       getGraalvmClassRegistry()
           .serializerClassMap
           .put(cls, getGraalvmSerializerClass(classInfo.serializer));
-      classInfo.serializer = null;
       classInfoCache = NIL_CLASS_INFO;
       if (RecordUtils.isRecord(cls)) {
         RecordUtils.getRecordConstructor(cls);
@@ -1783,8 +1777,15 @@ public class ClassResolver extends TypeResolver {
   /**
    * Ensure all compilation for serializers and accessors even for lazy 
initialized serializers.
    * This method will block until all compilation is done.
+   *
+   * <p>Note that this method should be invoked after all registrations and 
invoked only once.
+   * Repeated invocations will have no effect.
    */
   public void ensureSerializersCompiled() {
+    if (extRegistry.ensureSerializersCompiled) {
+      return;
+    }
+    extRegistry.ensureSerializersCompiled = true;
     try {
       fory.getJITContext().lock();
       Serializers.newSerializer(fory, LambdaSerializer.STUB_LAMBDA_CLASS, 
LambdaSerializer.class);
@@ -1793,7 +1794,12 @@ public class ClassResolver extends TypeResolver {
       classInfoMap.forEach(
           (cls, classInfo) -> {
             if (classInfo.serializer == null) {
-              getSerializer(classInfo.cls, isSerializable(classInfo.cls));
+              if (isSerializable(classInfo.cls)) {
+                createSerializer0(cls);
+              }
+              if (cls.isArray()) {
+                createSerializer0(TypeUtils.getArrayComponent(cls));
+              }
             }
           });
       if (GraalvmSupport.isGraalBuildtime()) {
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 564aa0666..69ab9f209 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
@@ -111,6 +111,29 @@ public abstract class TypeResolver {
     metaStringResolver = fory.getMetaStringResolver();
   }
 
+  public abstract void register(Class<?> type);
+
+  public abstract void register(Class<?> type, int id);
+
+  public abstract void register(Class<?> type, String namespace, String 
typeName);
+
+  public void register(String className) {
+    register(loadClass(className));
+  }
+
+  public void register(String className, int classId) {
+    register(loadClass(className), classId);
+  }
+
+  public void register(String className, String namespace, String typeName) {
+    register(loadClass(className), namespace, typeName);
+  }
+
+  public abstract void registerSerializer(Class<?> type, Serializer<?> 
serializer);
+
+  public abstract <T> void registerSerializer(
+      Class<T> type, Class<? extends Serializer> serializerClass);
+
   /**
    * Whether to track reference for this type. If false, reference tracing of 
subclasses may be
    * ignored too.
@@ -369,6 +392,10 @@ public abstract class TypeResolver {
     return loadClass(className, isEnum, arrayDims, 
fory.getConfig().deserializeNonexistentClass());
   }
 
+  final Class<?> loadClass(String className) {
+    return loadClass(className, false, -1, false);
+  }
+
   final Class<?> loadClass(
       String className, boolean isEnum, int arrayDims, boolean 
deserializeNonexistentClass) {
     extRegistry.typeChecker.checkType(this, className);
@@ -421,7 +448,15 @@ public abstract class TypeResolver {
       return false;
     }
     try {
+      ClassInfo classInfo = classInfoMap.get(cls);
+      Serializer<?> serializer = null;
+      if (classInfo != null) {
+        serializer = classInfo.serializer;
+      }
       getSerializerClass(cls, false);
+      if (classInfo != null && serializer == null) {
+        classInfo.serializer = null;
+      }
       return true;
     } catch (Throwable t) {
       return false;
@@ -663,5 +698,6 @@ public abstract class TypeResolver {
     final Map<Class, Map<String, GenericType>> classGenericTypes = new 
HashMap<>();
     final Map<List<ClassLoader>, CodeGenerator> codeGeneratorMap = new 
HashMap<>();
     final Set<ClassInfo> initialClassInfos = new HashSet<>();
+    boolean ensureSerializersCompiled;
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
index 599a865c5..3250c24eb 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
@@ -149,6 +149,7 @@ public class XtypeResolver extends TypeResolver {
     }
   }
 
+  @Override
   public void register(Class<?> type) {
     while (registeredTypeIds.contains(xtypeIdGenerator)) {
       xtypeIdGenerator++;
@@ -156,6 +157,7 @@ public class XtypeResolver extends TypeResolver {
     register(type, xtypeIdGenerator++);
   }
 
+  @Override
   public void register(Class<?> type, int userTypeId) {
     // ClassInfo[] has length of max type id. If the type id is too big, Fory 
will waste many
     // memory. We can relax this limit in the future.
@@ -204,6 +206,7 @@ public class XtypeResolver extends TypeResolver {
         xtypeId);
   }
 
+  @Override
   public void register(Class<?> type, String namespace, String typeName) {
     Preconditions.checkArgument(
         !typeName.contains("."),
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
index efc18543f..48d56e11d 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
@@ -333,6 +333,10 @@ public class ObjectStreamSerializer extends 
AbstractObjectSerializer {
                         this.slotsSerializer =
                             (CompatibleSerializerBase) 
Serializers.newSerializer(fory, type, c));
       }
+      if (GraalvmSupport.isGraalBuildtime()) {
+        // trigger serializer constructor method handle generate.
+        Serializers.newSerializer(fory, type, sc);
+      }
       if (sc == CompatibleSerializer.class || 
GraalvmSupport.isGraalBuildtime()) {
         // skip init generated serializer at graalvm build time
         this.slotsSerializer = new CompatibleSerializer(fory, type, 
fieldResolver);
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java 
b/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java
new file mode 100644
index 000000000..8d4a560d7
--- /dev/null
+++ b/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fory.serializer;
+
+import org.apache.fory.Fory;
+import org.apache.fory.ForyTestBase;
+import org.apache.fory.config.CompatibleMode;
+import org.apache.fory.config.ForyBuilder;
+import org.apache.fory.config.Language;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class RegisterTest extends ForyTestBase {
+
+  @Test(dataProvider = "enableCodegen")
+  public void testRegisterForCompatible(boolean enableCodegen) {
+    A a = new A();
+    a.setB(new B());
+    ForyBuilder builder =
+        Fory.builder()
+            .withLanguage(Language.JAVA)
+            .withCodegen(enableCodegen)
+            .withCompatibleMode(CompatibleMode.COMPATIBLE);
+
+    Fory fory1 = builder.build();
+    fory1.register(A.class, (short) 1000);
+
+    Fory fory2 = builder.build();
+    fory2.register(A.class, (short) 1000);
+    fory2.register(B.class, (short) 1001);
+
+    A a1 = fory1.deserialize(fory2.serialize(a), A.class);
+    Assert.assertNotNull(a1);
+    Assert.assertNull(a1.b);
+
+    Fory fory3 = builder.requireClassRegistration(false).build();
+    fory3.register(A.class, (short) 1000);
+
+    A a2 = fory2.deserialize(fory3.serialize(a), A.class);
+    Assert.assertNotNull(a2);
+    Assert.assertEquals(a2.b.getClass(), B.class);
+  }
+
+  public static class A {
+    private B b;
+
+    public void setB(B b) {
+      this.b = b;
+    }
+  }
+
+  public static class B {}
+}


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


Reply via email to