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


The following commit(s) were added to refs/heads/main by this push:
     new 13cfe6ce refactor(java): refactor object serializer for unifying 
xlang/java serialization in java (#2139)
13cfe6ce is described below

commit 13cfe6cedc9cfb41f86e11d3fe2790678fdeb5d2
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Apr 6 22:28:23 2025 +0800

    refactor(java): refactor object serializer for unifying xlang/java 
serialization in java (#2139)
    
    <!--
    **Thanks for contributing to Fury.**
    
    **If this is your first time opening a PR on fury, you can refer to
    
[CONTRIBUTING.md](https://github.com/apache/fury/blob/main/CONTRIBUTING.md).**
    
    Contribution Checklist
    
    - The **Apache Fury (incubating)** community has restrictions on the
    naming of pr titles. You can also find instructions in
    [CONTRIBUTING.md](https://github.com/apache/fury/blob/main/CONTRIBUTING.md).
    
    - Fury has a strong focus on performance. If the PR you submit will have
    an impact on performance, please benchmark it first and provide the
    benchmark result here.
    -->
    
    ## What does this PR do?
    
    <!-- Describe the purpose of this PR. -->
    
    ## Related issues
    
    <!--
    Is there any related issue? Please attach here.
    
    - #xxxx0
    - #xxxx1
    - #xxxx2
    -->
    
    ## Does this PR introduce any user-facing change?
    
    <!--
    If any user-facing interface changes, please [open an
    issue](https://github.com/apache/fury/issues/new/choose) describing the
    need to do so and update the document if necessary.
    -->
    
    - [ ] 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.
    -->
---
 .../src/main/java/org/apache/fury/Fury.java        |  14 +
 .../org/apache/fury/resolver/ClassResolver.java    |   1 +
 .../org/apache/fury/resolver/TypeResolver.java     |   2 +
 .../org/apache/fury/resolver/XtypeResolver.java    |   6 +
 .../fury/serializer/MetaSharedSerializer.java      |  20 +-
 .../serializer/NonexistentClassSerializers.java    |  10 +-
 .../apache/fury/serializer/ObjectSerializer.java   | 104 ++++---
 .../fury/serializer/SerializationBinding.java      | 306 +++++++++++++++++++++
 .../fury-core/native-image.properties              |   3 +
 9 files changed, 401 insertions(+), 65 deletions(-)

diff --git a/java/fury-core/src/main/java/org/apache/fury/Fury.java 
b/java/fury-core/src/main/java/org/apache/fury/Fury.java
index cf5be995..b564fc99 100644
--- a/java/fury-core/src/main/java/org/apache/fury/Fury.java
+++ b/java/fury-core/src/main/java/org/apache/fury/Fury.java
@@ -558,6 +558,11 @@ public final class Fury implements BaseFury {
     xwriteData(buffer, classInfo, obj);
   }
 
+  public void xwriteNonRef(MemoryBuffer buffer, Object obj, ClassInfo 
classInfo) {
+    xtypeResolver.writeClassInfo(buffer, classInfo);
+    xwriteData(buffer, classInfo, obj);
+  }
+
   private void xwriteData(MemoryBuffer buffer, ClassInfo classInfo, Object 
obj) {
     switch (classInfo.getXtypeId()) {
       case Types.BOOL:
@@ -1115,6 +1120,15 @@ public final class Fury implements BaseFury {
     }
   }
 
+  public Object xreadNullable(MemoryBuffer buffer, Serializer<Object> 
serializer) {
+    byte headFlag = buffer.readByte();
+    if (headFlag == Fury.NULL_FLAG) {
+      return null;
+    } else {
+      return serializer.xread(buffer);
+    }
+  }
+
   @Override
   public byte[] serializeJavaObject(Object obj) {
     MemoryBuffer buf = getBuffer();
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
index d864dfc9..83d62876 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
@@ -1793,6 +1793,7 @@ public class ClassResolver implements TypeResolver {
    * reduce map lookup to load class from binary.
    */
   @CodegenInvoke
+  @Override
   public ClassInfo readClassInfo(MemoryBuffer buffer, ClassInfo 
classInfoCache) {
     if (metaContextShareEnabled) {
       return readClassInfoWithMetaShare(buffer, 
fury.getSerializationContext().getMetaContext());
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/TypeResolver.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/TypeResolver.java
index 98b453a3..6c57e9cf 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/TypeResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/TypeResolver.java
@@ -38,6 +38,8 @@ public interface TypeResolver {
 
   ClassInfo readClassInfo(MemoryBuffer buffer, ClassInfoHolder 
classInfoHolder);
 
+  ClassInfo readClassInfo(MemoryBuffer buffer, ClassInfo classInfoCache);
+
   <T> Serializer<T> getSerializer(Class<T> cls);
 
   ClassInfo nilClassInfo();
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
index 41e6b4bc..fe68a9ef 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
@@ -419,6 +419,12 @@ public class XtypeResolver implements TypeResolver {
     return readClassInfo(buffer);
   }
 
+  @Override
+  public ClassInfo readClassInfo(MemoryBuffer buffer, ClassInfo 
classInfoCache) {
+    // TODO support type cache to speed up lookup
+    return readClassInfo(buffer);
+  }
+
   public ClassInfo readClassInfo(MemoryBuffer buffer) {
     long xtypeId = buffer.readVarUint32Small14();
     byte internalTypeId = (byte) xtypeId;
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
 
b/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
index ee962872..2eb1960f 100644
--- 
a/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
+++ 
b/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
@@ -75,6 +75,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
   private final RecordInfo recordInfo;
   private Serializer<T> serializer;
   private final ClassInfoHolder classInfoHolder;
+  private final SerializationBinding binding;
 
   public MetaSharedSerializer(Fury fury, Class<T> type, ClassDef classDef) {
     super(fury, type);
@@ -111,6 +112,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
     } else {
       recordInfo = null;
     }
+    binding = SerializationBinding.createBinding(fury);
   }
 
   @Override
@@ -141,6 +143,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
     Fury fury = this.fury;
     RefResolver refResolver = this.refResolver;
     ClassResolver classResolver = this.classResolver;
+    SerializationBinding binding = this.binding;
     refResolver.reference(obj);
     // read order: primitive,boxed,final,other,collection,map
     ObjectSerializer.FinalTypeField[] finalFields = this.finalFields;
@@ -157,7 +160,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
           assert fieldInfo.classInfo != null;
           Object fieldValue =
               ObjectSerializer.readFinalObjectFieldValue(
-                  fury, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
+                  binding, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
           fieldAccessor.putObject(obj, fieldValue);
         }
       } else {
@@ -167,13 +170,13 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
             fury.readRef(buffer, classInfoHolder);
           } else {
             ObjectSerializer.readFinalObjectFieldValue(
-                fury, refResolver, classResolver, fieldInfo, isFinal, buffer);
+                binding, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
           }
         }
       }
     }
     for (ObjectSerializer.GenericTypeField fieldInfo : otherFields) {
-      Object fieldValue = ObjectSerializer.readOtherFieldValue(fury, 
fieldInfo, buffer);
+      Object fieldValue = ObjectSerializer.readOtherFieldValue(binding, 
fieldInfo, buffer);
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       if (fieldAccessor != null) {
         fieldAccessor.putObject(obj, fieldValue);
@@ -182,7 +185,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
     Generics generics = fury.getGenerics();
     for (ObjectSerializer.GenericTypeField fieldInfo : containerFields) {
       Object fieldValue =
-          ObjectSerializer.readContainerFieldValue(fury, generics, fieldInfo, 
buffer);
+          ObjectSerializer.readContainerFieldValue(binding, generics, 
fieldInfo, buffer);
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       if (fieldAccessor != null) {
         fieldAccessor.putObject(obj, fieldValue);
@@ -196,6 +199,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
     Fury fury = this.fury;
     RefResolver refResolver = this.refResolver;
     ClassResolver classResolver = this.classResolver;
+    SerializationBinding binding = this.binding;
     // read order: primitive,boxed,final,other,collection,map
     ObjectSerializer.FinalTypeField[] finalFields = this.finalFields;
     for (int i = 0; i < finalFields.length; i++) {
@@ -211,7 +215,7 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
         } else {
           Object fieldValue =
               ObjectSerializer.readFinalObjectFieldValue(
-                  fury, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
+                  binding, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
           fields[counter++] = fieldValue;
         }
       } else {
@@ -221,20 +225,20 @@ public class MetaSharedSerializer<T> extends 
AbstractObjectSerializer<T> {
             fury.readRef(buffer, classInfoHolder);
           } else {
             ObjectSerializer.readFinalObjectFieldValue(
-                fury, refResolver, classResolver, fieldInfo, isFinal, buffer);
+                binding, refResolver, classResolver, fieldInfo, isFinal, 
buffer);
           }
         }
         fields[counter++] = null;
       }
     }
     for (ObjectSerializer.GenericTypeField fieldInfo : otherFields) {
-      Object fieldValue = ObjectSerializer.readOtherFieldValue(fury, 
fieldInfo, buffer);
+      Object fieldValue = ObjectSerializer.readOtherFieldValue(binding, 
fieldInfo, buffer);
       fields[counter++] = fieldValue;
     }
     Generics generics = fury.getGenerics();
     for (ObjectSerializer.GenericTypeField fieldInfo : containerFields) {
       Object fieldValue =
-          ObjectSerializer.readContainerFieldValue(fury, generics, fieldInfo, 
buffer);
+          ObjectSerializer.readContainerFieldValue(binding, generics, 
fieldInfo, buffer);
       fields[counter++] = fieldValue;
     }
   }
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
 
b/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
index bbdd972e..26d48f1b 100644
--- 
a/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
+++ 
b/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
@@ -70,12 +70,14 @@ public final class NonexistentClassSerializers {
     private final ClassDef classDef;
     private final ClassInfoHolder classInfoHolder;
     private final LongMap<ClassFieldsInfo> fieldsInfoMap;
+    private final SerializationBinding binding;
 
     public NonexistentClassSerializer(Fury fury, ClassDef classDef) {
       super(fury, NonexistentClass.NonexistentMetaShared.class);
       this.classDef = classDef;
       classInfoHolder = fury.getClassResolver().nilClassInfoHolder();
       fieldsInfoMap = new LongMap<>();
+      binding = SerializationBinding.createBinding(fury);
       Preconditions.checkArgument(fury.getConfig().isMetaShareEnabled());
     }
 
@@ -146,7 +148,7 @@ public final class NonexistentClassSerializers {
       for (ObjectSerializer.GenericTypeField fieldInfo : 
fieldsInfo.containerFields) {
         Object fieldValue = value.get(fieldInfo.qualifiedFieldName);
         ObjectSerializer.writeContainerFieldValue(
-            fury, refResolver, classResolver, generics, fieldInfo, buffer, 
fieldValue);
+            binding, refResolver, classResolver, generics, fieldInfo, buffer, 
fieldValue);
       }
     }
 
@@ -205,19 +207,19 @@ public final class NonexistentClassSerializers {
           } else {
             fieldValue =
                 ObjectSerializer.readFinalObjectFieldValue(
-                    fury, refResolver, classResolver, fieldInfo, isFinal[i], 
buffer);
+                    binding, refResolver, classResolver, fieldInfo, 
isFinal[i], buffer);
           }
         }
         entries.add(new MapEntry(fieldInfo.qualifiedFieldName, fieldValue));
       }
       for (ObjectSerializer.GenericTypeField fieldInfo : 
fieldsInfo.otherFields) {
-        Object fieldValue = ObjectSerializer.readOtherFieldValue(fury, 
fieldInfo, buffer);
+        Object fieldValue = ObjectSerializer.readOtherFieldValue(binding, 
fieldInfo, buffer);
         entries.add(new MapEntry(fieldInfo.qualifiedFieldName, fieldValue));
       }
       Generics generics = fury.getGenerics();
       for (ObjectSerializer.GenericTypeField fieldInfo : 
fieldsInfo.containerFields) {
         Object fieldValue =
-            ObjectSerializer.readContainerFieldValue(fury, generics, 
fieldInfo, buffer);
+            ObjectSerializer.readContainerFieldValue(binding, generics, 
fieldInfo, buffer);
         entries.add(new MapEntry(fieldInfo.qualifiedFieldName, fieldValue));
       }
       obj.setEntries(entries);
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java 
b/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
index fd640ebf..0d255bb9 100644
--- 
a/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
+++ 
b/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
@@ -38,6 +38,7 @@ import org.apache.fury.reflect.FieldAccessor;
 import org.apache.fury.resolver.ClassInfo;
 import org.apache.fury.resolver.ClassResolver;
 import org.apache.fury.resolver.RefResolver;
+import org.apache.fury.resolver.TypeResolver;
 import org.apache.fury.type.Descriptor;
 import org.apache.fury.type.DescriptorGrouper;
 import org.apache.fury.type.Generics;
@@ -73,6 +74,8 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
   private final GenericTypeField[] otherFields;
   private final GenericTypeField[] containerFields;
   private final int classVersionHash;
+  private final SerializationBinding binding;
+  private final TypeResolver typeResolver;
 
   public ObjectSerializer(Fury fury, Class<T> cls) {
     this(fury, cls, true);
@@ -80,12 +83,14 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
 
   public ObjectSerializer(Fury fury, Class<T> cls, boolean resolveParent) {
     super(fury, cls);
+    binding = SerializationBinding.createBinding(fury);
     // avoid recursive building serializers.
     // Use `setSerializerIfAbsent` to avoid overwriting existing serializer 
for class when used
     // as data serializer.
     if (resolveParent) {
       classResolver.setSerializerIfAbsent(cls, this);
     }
+    typeResolver = fury.isCrossLanguage() ? fury.getXtypeResolver() : 
classResolver;
     Collection<Descriptor> descriptors;
     boolean shareMeta = fury.getConfig().isMetaShareEnabled();
     if (shareMeta) {
@@ -128,30 +133,25 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
   public void write(MemoryBuffer buffer, T value) {
     Fury fury = this.fury;
     RefResolver refResolver = this.refResolver;
-    ClassResolver classResolver = this.classResolver;
     if (fury.checkClassVersion()) {
       buffer.writeInt32(classVersionHash);
     }
     // write order: primitive,boxed,final,other,collection,map
-    writeFinalFields(buffer, value, fury, refResolver, classResolver);
+    writeFinalFields(buffer, value, fury, refResolver, typeResolver);
     for (GenericTypeField fieldInfo : otherFields) {
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       Object fieldValue = fieldAccessor.getObject(value);
       if (fieldInfo.trackingRef) {
-        fury.writeRef(buffer, fieldValue, fieldInfo.classInfoHolder);
+        binding.writeRef(buffer, fieldValue, fieldInfo.classInfoHolder);
       } else {
-        fury.writeNullable(buffer, fieldValue, fieldInfo.classInfoHolder);
+        binding.writeNullable(buffer, fieldValue, fieldInfo.classInfoHolder);
       }
     }
-    writeContainerFields(buffer, value, fury, refResolver, classResolver);
+    writeContainerFields(buffer, value, fury, refResolver, typeResolver);
   }
 
   private void writeFinalFields(
-      MemoryBuffer buffer,
-      T value,
-      Fury fury,
-      RefResolver refResolver,
-      ClassResolver classResolver) {
+      MemoryBuffer buffer, T value, Fury fury, RefResolver refResolver, 
TypeResolver typeResolver) {
     FinalTypeField[] finalFields = this.finalFields;
     boolean metaShareEnabled = fury.getConfig().isMetaShareEnabled();
     for (int i = 0; i < finalFields.length; i++) {
@@ -164,21 +164,21 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
           Serializer<Object> serializer = fieldInfo.classInfo.getSerializer();
           if (!metaShareEnabled || isFinal[i]) {
             if (!fieldInfo.trackingRef) {
-              fury.writeNullable(buffer, fieldValue, serializer);
+              binding.writeNullable(buffer, fieldValue, serializer);
             } else {
               // whether tracking ref is recorded in `fieldInfo.serializer`, 
so it's still
               // consistent with jit serializer.
-              fury.writeRef(buffer, fieldValue, serializer);
+              binding.writeRef(buffer, fieldValue, serializer);
             }
           } else {
             if (fieldInfo.trackingRef && serializer.needToWriteRef()) {
               if (!refResolver.writeRefOrNull(buffer, fieldValue)) {
-                classResolver.writeClassInfo(buffer, fieldInfo.classInfo);
+                typeResolver.writeClassInfo(buffer, fieldInfo.classInfo);
                 // No generics for field, no need to update `depth`.
-                serializer.write(buffer, fieldValue);
+                binding.write(buffer, serializer, fieldValue);
               }
             } else {
-              fury.writeNullable(buffer, fieldValue, fieldInfo.classInfo);
+              binding.writeNullable(buffer, fieldValue, fieldInfo.classInfo);
             }
           }
         }
@@ -187,24 +187,20 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
   }
 
   private void writeContainerFields(
-      MemoryBuffer buffer,
-      T value,
-      Fury fury,
-      RefResolver refResolver,
-      ClassResolver classResolver) {
+      MemoryBuffer buffer, T value, Fury fury, RefResolver refResolver, 
TypeResolver typeResolver) {
     Generics generics = fury.getGenerics();
     for (GenericTypeField fieldInfo : containerFields) {
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       Object fieldValue = fieldAccessor.getObject(value);
       writeContainerFieldValue(
-          fury, refResolver, classResolver, generics, fieldInfo, buffer, 
fieldValue);
+          binding, refResolver, typeResolver, generics, fieldInfo, buffer, 
fieldValue);
     }
   }
 
   static void writeContainerFieldValue(
-      Fury fury,
+      SerializationBinding binding,
       RefResolver refResolver,
-      ClassResolver classResolver,
+      TypeResolver typeResolver,
       Generics generics,
       GenericTypeField fieldInfo,
       MemoryBuffer buffer,
@@ -212,9 +208,9 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
     if (fieldInfo.trackingRef) {
       if (!refResolver.writeRefOrNull(buffer, fieldValue)) {
         ClassInfo classInfo =
-            classResolver.getClassInfo(fieldValue.getClass(), 
fieldInfo.classInfoHolder);
+            typeResolver.getClassInfo(fieldValue.getClass(), 
fieldInfo.classInfoHolder);
         generics.pushGenericType(fieldInfo.genericType);
-        fury.writeNonRef(buffer, fieldValue, classInfo);
+        binding.writeNonRef(buffer, fieldValue, classInfo);
         generics.popGenericType();
       }
     } else {
@@ -223,10 +219,10 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
       } else {
         buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
         generics.pushGenericType(fieldInfo.genericType);
-        fury.writeNonRef(
+        binding.writeNonRef(
             buffer,
             fieldValue,
-            classResolver.getClassInfo(fieldValue.getClass(), 
fieldInfo.classInfoHolder));
+            typeResolver.getClassInfo(fieldValue.getClass(), 
fieldInfo.classInfoHolder));
         generics.popGenericType();
       }
     }
@@ -253,7 +249,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
   public Object[] readFields(MemoryBuffer buffer) {
     Fury fury = this.fury;
     RefResolver refResolver = this.refResolver;
-    ClassResolver classResolver = this.classResolver;
+    TypeResolver typeResolver = this.typeResolver;
     if (fury.checkClassVersion()) {
       int hash = buffer.readInt32();
       checkClassVersion(fury, hash, classVersionHash);
@@ -273,17 +269,18 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
         fieldValues[counter++] = Serializers.readPrimitiveValue(fury, buffer, 
classId);
       } else {
         Object fieldValue =
-            readFinalObjectFieldValue(fury, refResolver, classResolver, 
fieldInfo, isFinal, buffer);
+            readFinalObjectFieldValue(
+                binding, refResolver, typeResolver, fieldInfo, isFinal, 
buffer);
         fieldValues[counter++] = fieldValue;
       }
     }
     for (GenericTypeField fieldInfo : otherFields) {
-      Object fieldValue = readOtherFieldValue(fury, fieldInfo, buffer);
+      Object fieldValue = readOtherFieldValue(binding, fieldInfo, buffer);
       fieldValues[counter++] = fieldValue;
     }
     Generics generics = fury.getGenerics();
     for (GenericTypeField fieldInfo : containerFields) {
-      Object fieldValue = readContainerFieldValue(fury, generics, fieldInfo, 
buffer);
+      Object fieldValue = readContainerFieldValue(binding, generics, 
fieldInfo, buffer);
       fieldValues[counter++] = fieldValue;
     }
     return fieldValues;
@@ -292,7 +289,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
   public T readAndSetFields(MemoryBuffer buffer, T obj) {
     Fury fury = this.fury;
     RefResolver refResolver = this.refResolver;
-    ClassResolver classResolver = this.classResolver;
+    TypeResolver typeResolver = this.typeResolver;
     if (fury.checkClassVersion()) {
       int hash = buffer.readInt32();
       checkClassVersion(fury, hash, classVersionHash);
@@ -308,18 +305,19 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
       if (readPrimitiveFieldValueFailed(fury, buffer, obj, fieldAccessor, 
classId)
           && readBasicObjectFieldValueFailed(fury, buffer, obj, fieldAccessor, 
classId)) {
         Object fieldValue =
-            readFinalObjectFieldValue(fury, refResolver, classResolver, 
fieldInfo, isFinal, buffer);
+            readFinalObjectFieldValue(
+                binding, refResolver, typeResolver, fieldInfo, isFinal, 
buffer);
         fieldAccessor.putObject(obj, fieldValue);
       }
     }
     for (GenericTypeField fieldInfo : otherFields) {
-      Object fieldValue = readOtherFieldValue(fury, fieldInfo, buffer);
+      Object fieldValue = readOtherFieldValue(binding, fieldInfo, buffer);
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       fieldAccessor.putObject(obj, fieldValue);
     }
     Generics generics = fury.getGenerics();
     for (GenericTypeField fieldInfo : containerFields) {
-      Object fieldValue = readContainerFieldValue(fury, generics, fieldInfo, 
buffer);
+      Object fieldValue = readContainerFieldValue(binding, generics, 
fieldInfo, buffer);
       FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
       fieldAccessor.putObject(obj, fieldValue);
     }
@@ -331,9 +329,9 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
    * because primitive field doesn't write null flag.
    */
   static Object readFinalObjectFieldValue(
-      Fury fury,
+      SerializationBinding binding,
       RefResolver refResolver,
-      ClassResolver classResolver,
+      TypeResolver typeResolver,
       FinalTypeField fieldInfo,
       boolean isFinal,
       MemoryBuffer buffer) {
@@ -341,16 +339,16 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
     Object fieldValue;
     if (isFinal) {
       if (!fieldInfo.trackingRef) {
-        return fury.readNullable(buffer, serializer);
+        return binding.readNullable(buffer, serializer);
       }
       // whether tracking ref is recorded in `fieldInfo.serializer`, so it's 
still
       // consistent with jit serializer.
-      fieldValue = fury.readRef(buffer, serializer);
+      fieldValue = binding.readRef(buffer, serializer);
     } else {
       if (serializer.needToWriteRef()) {
         int nextReadRefId = refResolver.tryPreserveRefId(buffer);
         if (nextReadRefId >= Fury.NOT_NULL_VALUE_FLAG) {
-          classResolver.readClassInfo(buffer, fieldInfo.classInfo);
+          typeResolver.readClassInfo(buffer, fieldInfo.classInfo);
           fieldValue = serializer.read(buffer);
           refResolver.setReadObject(nextReadRefId, fieldValue);
         } else {
@@ -361,7 +359,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
         if (headFlag == Fury.NULL_FLAG) {
           fieldValue = null;
         } else {
-          classResolver.readClassInfo(buffer, fieldInfo.classInfo);
+          typeResolver.readClassInfo(buffer, fieldInfo.classInfo);
           fieldValue = serializer.read(buffer);
         }
       }
@@ -369,27 +367,31 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
     return fieldValue;
   }
 
-  static Object readOtherFieldValue(Fury fury, GenericTypeField fieldInfo, 
MemoryBuffer buffer) {
+  static Object readOtherFieldValue(
+      SerializationBinding binding, GenericTypeField fieldInfo, MemoryBuffer 
buffer) {
     Object fieldValue;
     if (fieldInfo.trackingRef) {
-      fieldValue = fury.readRef(buffer, fieldInfo.classInfoHolder);
+      fieldValue = binding.readRef(buffer, fieldInfo.classInfoHolder);
     } else {
       byte headFlag = buffer.readByte();
       if (headFlag == Fury.NULL_FLAG) {
         fieldValue = null;
       } else {
-        fieldValue = fury.readNonRef(buffer, fieldInfo.classInfoHolder);
+        fieldValue = binding.readNonRef(buffer, fieldInfo.classInfoHolder);
       }
     }
     return fieldValue;
   }
 
   static Object readContainerFieldValue(
-      Fury fury, Generics generics, GenericTypeField fieldInfo, MemoryBuffer 
buffer) {
+      SerializationBinding binding,
+      Generics generics,
+      GenericTypeField fieldInfo,
+      MemoryBuffer buffer) {
     Object fieldValue;
     if (fieldInfo.trackingRef) {
       generics.pushGenericType(fieldInfo.genericType);
-      fieldValue = fury.readRef(buffer, fieldInfo.classInfoHolder);
+      fieldValue = binding.readRef(buffer, fieldInfo.classInfoHolder);
       generics.popGenericType();
     } else {
       byte headFlag = buffer.readByte();
@@ -397,7 +399,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
         fieldValue = null;
       } else {
         generics.pushGenericType(fieldInfo.genericType);
-        fieldValue = fury.readNonRef(buffer, fieldInfo.classInfoHolder);
+        fieldValue = binding.readNonRef(buffer, fieldInfo.classInfoHolder);
         generics.popGenericType();
       }
     }
@@ -649,9 +651,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
         fieldAccessor.putObject(targetObject, fury.readJavaStringRef(buffer));
         return false;
       default:
-        {
-          return true;
-        }
+        return true;
     }
   }
 
@@ -690,9 +690,7 @@ public final class ObjectSerializer<T> extends 
AbstractObjectSerializer<T> {
         Platform.putObject(targetObject, fieldOffset, 
fury.readJavaStringRef(buffer));
         return false;
       default:
-        {
-          return true;
-        }
+        return true;
     }
   }
 
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
 
b/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
new file mode 100644
index 00000000..d21fa404
--- /dev/null
+++ 
b/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
@@ -0,0 +1,306 @@
+/*
+ * 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.fury.serializer;
+
+import org.apache.fury.Fury;
+import org.apache.fury.memory.MemoryBuffer;
+import org.apache.fury.resolver.ClassInfo;
+import org.apache.fury.resolver.ClassInfoHolder;
+import org.apache.fury.resolver.ClassResolver;
+import org.apache.fury.resolver.XtypeResolver;
+
+// This polymorphic interface has cost, do not expose it as a public class
+// If it's used in other packages in fury, duplicate it in those packages.
+@SuppressWarnings({"rawtypes", "unchecked"})
+// noinspection Duplicates
+interface SerializationBinding {
+  <T> void writeRef(MemoryBuffer buffer, T obj);
+
+  <T> void writeRef(MemoryBuffer buffer, T obj, Serializer<T> serializer);
+
+  void writeRef(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder);
+
+  void writeNonRef(MemoryBuffer buffer, Object obj);
+
+  void writeNonRef(MemoryBuffer buffer, Object obj, ClassInfo classInfo);
+
+  void writeNullable(MemoryBuffer buffer, Object obj);
+
+  void writeNullable(MemoryBuffer buffer, Object obj, Serializer serializer);
+
+  void writeNullable(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder);
+
+  void writeNullable(MemoryBuffer buffer, Object obj, ClassInfo classInfo);
+
+  void write(MemoryBuffer buffer, Serializer serializer, Object value);
+
+  Object read(MemoryBuffer buffer, Serializer serializer);
+
+  <T> T readRef(MemoryBuffer buffer, Serializer<T> serializer);
+
+  Object readRef(MemoryBuffer buffer, ClassInfoHolder classInfoHolder);
+
+  Object readRef(MemoryBuffer buffer);
+
+  Object readNonRef(MemoryBuffer buffer);
+
+  Object readNonRef(MemoryBuffer buffer, ClassInfoHolder classInfoHolder);
+
+  Object readNullable(MemoryBuffer buffer, Serializer<Object> serializer);
+
+  static SerializationBinding createBinding(Fury fury) {
+    if (fury.isCrossLanguage()) {
+      return new XlangSerializationBinding(fury);
+    } else {
+      return new JavaSerializationBinding(fury);
+    }
+  }
+
+  final class JavaSerializationBinding implements SerializationBinding {
+    private final Fury fury;
+    private final ClassResolver classResolver;
+
+    JavaSerializationBinding(Fury fury) {
+      this.fury = fury;
+      classResolver = fury.getClassResolver();
+    }
+
+    @Override
+    public <T> void writeRef(MemoryBuffer buffer, T obj) {
+      fury.writeRef(buffer, obj);
+    }
+
+    @Override
+    public <T> void writeRef(MemoryBuffer buffer, T obj, Serializer<T> 
serializer) {
+      fury.writeRef(buffer, obj, serializer);
+    }
+
+    @Override
+    public void writeRef(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder) {
+      fury.writeRef(buffer, obj, classInfoHolder);
+    }
+
+    @Override
+    public <T> T readRef(MemoryBuffer buffer, Serializer<T> serializer) {
+      return fury.readRef(buffer, serializer);
+    }
+
+    @Override
+    public Object readRef(MemoryBuffer buffer, ClassInfoHolder 
classInfoHolder) {
+      return fury.readRef(buffer, classInfoHolder);
+    }
+
+    @Override
+    public Object readRef(MemoryBuffer buffer) {
+      return fury.readRef(buffer);
+    }
+
+    @Override
+    public Object readNonRef(MemoryBuffer buffer) {
+      return fury.readNonRef(buffer);
+    }
+
+    @Override
+    public Object readNonRef(MemoryBuffer buffer, ClassInfoHolder 
classInfoHolder) {
+      return fury.readNonRef(buffer, classInfoHolder);
+    }
+
+    @Override
+    public Object readNullable(MemoryBuffer buffer, Serializer<Object> 
serializer) {
+      return fury.readNullable(buffer, serializer);
+    }
+
+    @Override
+    public void write(MemoryBuffer buffer, Serializer serializer, Object 
value) {
+      serializer.write(buffer, value);
+    }
+
+    @Override
+    public Object read(MemoryBuffer buffer, Serializer serializer) {
+      return serializer.read(buffer);
+    }
+
+    @Override
+    public void writeNonRef(MemoryBuffer buffer, Object obj) {
+      fury.writeNonRef(buffer, obj);
+    }
+
+    @Override
+    public void writeNonRef(MemoryBuffer buffer, Object obj, ClassInfo 
classInfo) {
+      fury.writeNonRef(buffer, obj, classInfo);
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        writeNonRef(buffer, obj);
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, Serializer 
serializer) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        serializer.write(buffer, obj);
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        fury.writeNonRef(buffer, obj, 
classResolver.getClassInfo(obj.getClass(), classInfoHolder));
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, ClassInfo 
classInfo) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        fury.writeNonRef(buffer, obj, classInfo);
+      }
+    }
+  }
+
+  final class XlangSerializationBinding implements SerializationBinding {
+
+    private final Fury fury;
+    private final XtypeResolver xtypeResolver;
+
+    XlangSerializationBinding(Fury fury) {
+      this.fury = fury;
+      xtypeResolver = fury.getXtypeResolver();
+    }
+
+    @Override
+    public <T> void writeRef(MemoryBuffer buffer, T obj) {
+      fury.xwriteRef(buffer, obj);
+    }
+
+    @Override
+    public <T> void writeRef(MemoryBuffer buffer, T obj, Serializer<T> 
serializer) {
+      fury.xwriteRef(buffer, obj, serializer);
+    }
+
+    @Override
+    public void writeRef(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder) {
+      fury.xwriteRef(buffer, obj);
+    }
+
+    @Override
+    public <T> T readRef(MemoryBuffer buffer, Serializer<T> serializer) {
+      return (T) fury.xreadRef(buffer, serializer);
+    }
+
+    @Override
+    public Object readRef(MemoryBuffer buffer, ClassInfoHolder 
classInfoHolder) {
+      return fury.xreadRef(buffer);
+    }
+
+    @Override
+    public Object readRef(MemoryBuffer buffer) {
+      return fury.xreadRef(buffer);
+    }
+
+    @Override
+    public Object readNonRef(MemoryBuffer buffer) {
+      return fury.xreadNonRef(buffer);
+    }
+
+    @Override
+    public Object readNonRef(MemoryBuffer buffer, ClassInfoHolder 
classInfoHolder) {
+      return fury.xreadNonRef(buffer, xtypeResolver.readClassInfo(buffer, 
classInfoHolder));
+    }
+
+    @Override
+    public Object readNullable(MemoryBuffer buffer, Serializer<Object> 
serializer) {
+      return fury.xreadNullable(buffer, serializer);
+    }
+
+    @Override
+    public void write(MemoryBuffer buffer, Serializer serializer, Object 
value) {
+      serializer.xwrite(buffer, value);
+    }
+
+    @Override
+    public Object read(MemoryBuffer buffer, Serializer serializer) {
+      return serializer.xread(buffer);
+    }
+
+    @Override
+    public void writeNonRef(MemoryBuffer buffer, Object obj) {
+      fury.xwriteNonRef(buffer, obj);
+    }
+
+    @Override
+    public void writeNonRef(MemoryBuffer buffer, Object obj, ClassInfo 
classInfo) {
+      fury.xwriteNonRef(buffer, obj, classInfo);
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        fury.xwriteNonRef(buffer, obj);
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, Serializer 
serializer) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        serializer.xwrite(buffer, obj);
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, ClassInfoHolder 
classInfoHolder) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        fury.xwriteNonRef(buffer, obj, 
xtypeResolver.getClassInfo(obj.getClass(), classInfoHolder));
+      }
+    }
+
+    @Override
+    public void writeNullable(MemoryBuffer buffer, Object obj, ClassInfo 
classInfo) {
+      if (obj == null) {
+        buffer.writeByte(Fury.NULL_FLAG);
+      } else {
+        buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
+        fury.xwriteNonRef(buffer, obj, classInfo);
+      }
+    }
+  }
+}
diff --git 
a/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
 
b/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
index 18960e4c..fd8b3e86 100644
--- 
a/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
+++ 
b/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
@@ -282,6 +282,9 @@ 
Args=--initialize-at-build-time=org.apache.fury.memory.MemoryBuffer,\
     org.apache.fury.serializer.collection.SerializationBinding,\
     
org.apache.fury.serializer.collection.SerializationBinding$XlangSerializationBinding,\
     
org.apache.fury.serializer.collection.SerializationBinding$JavaSerializationBinding,\
+    org.apache.fury.serializer.SerializationBinding,\
+    org.apache.fury.serializer.SerializationBinding$XlangSerializationBinding,\
+    org.apache.fury.serializer.SerializationBinding$JavaSerializationBinding,\
     org.apache.fury.serializer.ArraySerializers$BooleanArraySerializer,\
     org.apache.fury.serializer.ArraySerializers$ByteArraySerializer,\
     org.apache.fury.serializer.ArraySerializers$CharArraySerializer,\


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


Reply via email to