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 73b62f9d feat(java): array row encoder supports set of interface type 
(#2333)
73b62f9d is described below

commit 73b62f9d3c62602aea5033bfe65d8dfb20f39c25
Author: Steven Schlansker <[email protected]>
AuthorDate: Thu Jun 12 20:41:03 2025 -0700

    feat(java): array row encoder supports set of interface type (#2333)
    
    ## What does this PR do?
    
    improve array row encoder to support custom collections that are not
    List, for example TreeSet
    also supports interface types as value
    
    Co-authored-by: Shawn Yang <[email protected]>
---
 .../main/java/org/apache/fory/type/TypeUtils.java  |  9 ++++-
 .../fory/format/encoder/ArrayEncoderBuilder.java   |  3 +-
 .../org/apache/fory/format/encoder/Encoders.java   | 13 ++++---
 .../format/encoder/ImplementInterfaceTest.java     | 40 ++++++++++++++++++++++
 4 files changed, 58 insertions(+), 7 deletions(-)

diff --git a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java 
b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
index 1c7b3946..6bc0b4b0 100644
--- a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
+++ b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
@@ -599,7 +599,8 @@ public class TypeUtils {
 
   public static boolean isBean(TypeRef<?> typeRef, TypeResolutionContext ctx) {
     Class<?> cls = getRawType(typeRef);
-    if (ctx.isSynthesizeInterfaces() && (RecordUtils.isRecord(cls) || 
(cls.isInterface()))) {
+    if (ctx.isSynthesizeInterfaces()
+        && (RecordUtils.isRecord(cls) || isSynthesizableInterface(cls))) {
       return true;
     }
     if (Modifier.isAbstract(cls.getModifiers()) || 
Modifier.isInterface(cls.getModifiers())) {
@@ -651,6 +652,12 @@ public class TypeUtils {
     }
   }
 
+  private static boolean isSynthesizableInterface(Class<?> cls) {
+    return cls.isInterface()
+        && !Collection.class.isAssignableFrom(cls)
+        && !Map.class.isAssignableFrom(cls);
+  }
+
   /** Check if <code>typeToken</code> is supported by row-format. */
   public static boolean isSupported(TypeRef<?> typeRef) {
     return isSupported(typeRef, new 
TypeResolutionContext(CustomTypeRegistry.EMPTY));
diff --git 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/ArrayEncoderBuilder.java
 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/ArrayEncoderBuilder.java
index 8937a66e..2865d62c 100644
--- 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/ArrayEncoderBuilder.java
+++ 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/ArrayEncoderBuilder.java
@@ -142,7 +142,8 @@ public class ArrayEncoderBuilder extends 
BaseBinaryEncoderBuilder {
     Expression.Reference inputObject =
         new Expression.Reference(ROOT_OBJECT_NAME, TypeUtils.COLLECTION_TYPE, 
false);
     Expression.Cast array =
-        new Expression.Cast(inputObject, arrayToken, 
ctx.newName(getRawType(arrayToken)));
+        new Expression.Cast(
+            inputObject, arrayToken, ctx.newName(getRawType(arrayToken)), 
false, false);
     expressions.add(array);
 
     Expression.Reference fieldExpr = new Expression.Reference(FIELD_NAME, 
ARROW_FIELD_TYPE, false);
diff --git 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java
index 020167f6..18845507 100644
--- 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java
+++ 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java
@@ -343,7 +343,7 @@ public class Encoders {
       Class<? extends Collection> arrayCls, Class<B> elementType) {
     Preconditions.checkNotNull(elementType);
 
-    return (ArrayEncoder<T>) arrayEncoder(TypeUtils.listOf(elementType), null);
+    return (ArrayEncoder<T>) arrayEncoder(TypeUtils.collectionOf(elementType), 
null);
   }
 
   /**
@@ -581,7 +581,8 @@ public class Encoders {
 
   private static Set<TypeRef<?>> beanSet(TypeRef<?> token) {
     Set<TypeRef<?>> set = new HashSet<>();
-    if (TypeUtils.isBean(token)) {
+    if (TypeUtils.isBean(
+        token, new 
TypeResolutionContext(CustomTypeEncoderRegistry.customTypeHandler(), true))) {
       set.add(token);
       return set;
     }
@@ -645,6 +646,8 @@ public class Encoders {
   }
 
   private static void findBeanToken(TypeRef<?> typeRef, 
java.util.Set<TypeRef<?>> set) {
+    TypeResolutionContext typeCtx =
+        new 
TypeResolutionContext(CustomTypeEncoderRegistry.customTypeHandler(), true);
     Set<TypeRef<?>> visited = new LinkedHashSet<>();
     while (TypeUtils.ITERABLE_TYPE.isSupertypeOf(typeRef)
         || TypeUtils.MAP_TYPE.isSupertypeOf(typeRef)) {
@@ -654,20 +657,20 @@ public class Encoders {
       visited.add(typeRef);
       if (TypeUtils.ITERABLE_TYPE.isSupertypeOf(typeRef)) {
         typeRef = TypeUtils.getElementType(typeRef);
-        if (TypeUtils.isBean(typeRef)) {
+        if (TypeUtils.isBean(typeRef, typeCtx)) {
           set.add(typeRef);
         }
         findBeanToken(typeRef, set);
       } else {
         Tuple2<TypeRef<?>, TypeRef<?>> tuple2 = 
TypeUtils.getMapKeyValueType(typeRef);
-        if (TypeUtils.isBean(tuple2.f0)) {
+        if (TypeUtils.isBean(tuple2.f0, typeCtx)) {
           set.add(tuple2.f0);
         } else {
           typeRef = tuple2.f0;
           findBeanToken(tuple2.f0, set);
         }
 
-        if (TypeUtils.isBean(tuple2.f1)) {
+        if (TypeUtils.isBean(tuple2.f1, typeCtx)) {
           set.add(tuple2.f1);
         } else {
           typeRef = tuple2.f1;
diff --git 
a/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java
 
b/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java
index 82d6284c..67047d3f 100644
--- 
a/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java
+++ 
b/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java
@@ -22,11 +22,14 @@ package org.apache.fory.format.encoder;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
+import java.util.TreeSet;
 import lombok.Data;
 import org.apache.fory.annotation.ForyField;
+import org.apache.fory.format.row.binary.BinaryArray;
 import org.apache.fory.format.row.binary.BinaryRow;
 import org.apache.fory.memory.MemoryBuffer;
 import org.apache.fory.memory.MemoryUtils;
+import org.apache.fory.reflect.TypeRef;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -258,4 +261,41 @@ public class ImplementInterfaceTest {
     final ListOuter deserializedBean = encoder.fromRow(row);
     Assert.assertEquals(deserializedBean.f1().get(0).f1(), 42);
   }
+
+  public interface Value extends Comparable<Value> {
+    int v();
+
+    @Override
+    default int compareTo(final Value o) {
+      return Integer.compare(v(), o.v());
+    }
+  }
+
+  public static class ValueImpl implements Value {
+    int v;
+
+    public ValueImpl(final int v) {
+      this.v = v;
+    }
+
+    @Override
+    public int v() {
+      return v;
+    }
+  }
+
+  @Test
+  public void testTreeSetOfInterface() {
+    final ArrayEncoder<TreeSet<Value>> encoder =
+        Encoders.arrayEncoder(new TypeRef<TreeSet<Value>>() {});
+    final TreeSet<Value> expected = new TreeSet<Value>();
+    expected.add(new ValueImpl(1));
+    expected.add(new ValueImpl(3));
+    expected.add(new ValueImpl(5));
+    final BinaryArray array = encoder.toArray(expected);
+    final MemoryBuffer buffer = array.getBuffer();
+    array.pointTo(buffer, 0, buffer.size());
+    final TreeSet<Value> deserializedBean = encoder.fromArray(array);
+    Assert.assertEquals(deserializedBean, expected);
+  }
 }


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

Reply via email to