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 8d028b47 fix(java): row encoder interface synthesis handle `(Optional) 
null` correctly (#2306)
8d028b47 is described below

commit 8d028b47d900a31d86c7b67c37f952ac36b30d6a
Author: Steven Schlansker <[email protected]>
AuthorDate: Fri Jun 6 18:04:37 2025 -0700

    fix(java): row encoder interface synthesis handle `(Optional) null` 
correctly (#2306)
    
    ## What does this PR do?
    
    fix incorrect handling of lazy-read `(Optional) null` values
---
 .../fory/format/encoder/RowEncoderBuilder.java     |  6 ++++--
 .../format/encoder/ImplementInterfaceTest.java     | 23 ++++++++++++++++++++++
 .../apache/fory/format/encoder/OptionalTest.java   | 12 +++++++++++
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/RowEncoderBuilder.java
 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/RowEncoderBuilder.java
index cf351365..a82f368c 100644
--- 
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/RowEncoderBuilder.java
+++ 
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/RowEncoderBuilder.java
@@ -315,7 +315,6 @@ public class RowEncoderBuilder extends 
BaseBinaryEncoderBuilder {
     implClass.setClassName(generatedBeanImplName);
     implClass.implementsInterfaces(implClass.type(beanClass));
     implClass.addField(true, implClass.type(BinaryRow.class), "row", null);
-    implClass.addConstructor("this.row = row;", BinaryRow.class, "row");
 
     int numFields = schema.getFields().size();
     for (int i = 0; i < numFields; i++) {
@@ -330,7 +329,8 @@ public class RowEncoderBuilder extends 
BaseBinaryEncoderBuilder {
         getterImpl = new Expression.Return(decodeValue);
       } else {
         String fieldName = "f" + i + "_" + d.getName();
-        implClass.addField(fieldType.getRawType(), fieldName);
+        implClass.addField(
+            false, ctx.type(fieldType.getRawType()), fieldName, 
nullValue(fieldType));
 
         Expression fieldRef = new Expression.Reference(fieldName, fieldType, 
true);
         Expression storeValue =
@@ -353,6 +353,8 @@ public class RowEncoderBuilder extends 
BaseBinaryEncoderBuilder {
       implClass.addMethod(
           d.getName(), getterImpl.genCode(implClass).code(), 
fieldType.getRawType());
     }
+    // Note: adding constructor captures init code, so must happen after all 
fields are collected
+    implClass.addConstructor("this.row = row;", BinaryRow.class, "row");
 
     return implClass;
   }
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 df18bede..70af5f1b 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
@@ -19,6 +19,7 @@
 
 package org.apache.fory.format.encoder;
 
+import java.util.Optional;
 import lombok.Data;
 import org.apache.fory.annotation.ForyField;
 import org.apache.fory.format.row.binary.BinaryRow;
@@ -128,4 +129,26 @@ public class ImplementInterfaceTest {
       throw new AssertionError();
     }
   }
+
+  public interface OptionalType {
+    Optional<String> f1();
+  }
+
+  static class OptionalTypeImpl implements OptionalType {
+    @Override
+    public Optional<String> f1() {
+      return null;
+    }
+  }
+
+  @Test
+  public void testNullOptional() {
+    final OptionalType bean1 = new OptionalTypeImpl();
+    final RowEncoder<OptionalType> encoder = Encoders.bean(OptionalType.class);
+    final BinaryRow row = encoder.toRow(bean1);
+    final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes());
+    row.pointTo(buffer, 0, buffer.size());
+    final OptionalType deserializedBean = encoder.fromRow(row);
+    Assert.assertEquals(deserializedBean.f1(), Optional.empty());
+  }
 }
diff --git 
a/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java
 
b/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java
index 3093cd3d..99e1f263 100644
--- 
a/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java
+++ 
b/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java
@@ -53,6 +53,18 @@ public class OptionalTest {
     Assert.assertEquals(deserializedBean, bean);
   }
 
+  @Test
+  public void testOptionalNull() {
+    final OptionalType bean = new OptionalType();
+    final RowEncoder<OptionalType> encoder = Encoders.bean(OptionalType.class);
+    final BinaryRow row = encoder.toRow(bean);
+    final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes());
+    row.pointTo(buffer, 0, buffer.size());
+    final OptionalType deserializedBean = encoder.fromRow(row);
+    Assert.assertEquals(deserializedBean.f1, Optional.empty());
+    Assert.assertEquals(deserializedBean.f2, Optional.empty());
+  }
+
   @Test
   public void testOptionalPresent() {
     final OptionalType bean = new OptionalType();


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

Reply via email to