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 6865924c8 fix(java): support inherited fields in xlang (#3838)
6865924c8 is described below

commit 6865924c883d98b92fafcddd1b9ee102517e42bc
Author: Shawn Yang <[email protected]>
AuthorDate: Mon Jul 13 17:42:52 2026 +0530

    fix(java): support inherited fields in xlang (#3838)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    Closes #3836
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence or equivalent persisted links of the
    final clean AI review results from both fresh reviewers described in
    `AI_POLICY.md`, the Fory-guided reviewer and the independent general
    reviewer, on the current PR diff or current HEAD after the latest code
    changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 .../main/java/org/apache/fory/meta/TypeDef.java    | 26 +++++++++++++++++-----
 .../java/org/apache/fory/meta/TypeDefEncoder.java  |  3 +--
 .../org/apache/fory/xlang/MetaShareXlangTest.java  | 22 ++++++++++++++++++
 3 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDef.java 
b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDef.java
index 5e8b33eac..bc1a26fca 100644
--- a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDef.java
+++ b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDef.java
@@ -367,8 +367,24 @@ public class TypeDef implements Serializable {
 
   private List<Descriptor> buildDescriptors(
       TypeResolver resolver, Class<?> cls, Collection<Descriptor> 
fieldDescriptors) {
+    boolean isXlang = resolver.isCrossLanguage();
     Map<String, Descriptor> descriptorsMap = new HashMap<>();
     Map<Short, Descriptor> fieldIdToDescriptorMap = new HashMap<>();
+    Map<String, Descriptor> xlangNameDescriptors = null;
+
+    if (isXlang) {
+      xlangNameDescriptors = new HashMap<>();
+      // Xlang TypeDef flattens inherited fields and does not encode their 
Java declaring class.
+      // Reuse the encoder's shadow/collision selection so name-based fields 
bind by the same
+      // language-neutral identifier on both the schema and local descriptor 
sides.
+      List<Descriptor> xlangDescriptors =
+          TypeDefEncoder.dropShadowedXlangNameFields(cls, new 
ArrayList<>(fieldDescriptors));
+      for (Descriptor descriptor : xlangDescriptors) {
+        if (!descriptor.hasForyFieldId()) {
+          xlangNameDescriptors.put(descriptor.getSnakeCaseName(), descriptor);
+        }
+      }
+    }
 
     for (Descriptor descriptor : fieldDescriptors) {
       String fullName = descriptor.getDeclaringClass() + "." + 
descriptor.getName();
@@ -390,7 +406,6 @@ public class TypeDef implements Serializable {
       }
     }
     List<Descriptor> descriptors = new ArrayList<>(fieldsInfo.size());
-    boolean isXlang = resolver.isCrossLanguage();
     Collection<Descriptor> remoteDescriptors = null;
     Map<String, Descriptor> remoteDescriptorsMap = null;
     Map<Short, Descriptor> remoteFieldIdToDescriptorMap = null;
@@ -400,15 +415,14 @@ public class TypeDef implements Serializable {
       Descriptor descriptor;
       if (fieldInfo.hasFieldId()) {
         descriptor = fieldIdToDescriptorMap.get(fieldInfo.getFieldId());
+      } else if (isXlang) {
+        descriptor =
+            xlangNameDescriptors.get(
+                
StringUtils.lowerCamelToLowerUnderscore(fieldInfo.getFieldName()));
       } else {
         String fieldName = fieldInfo.getFieldName();
         String definedClass = fieldInfo.getDefinedClass();
         descriptor = descriptorsMap.get(definedClass + "." + fieldName);
-        if (descriptor == null && isXlang) {
-          descriptor =
-              descriptorsMap.get(
-                  definedClass + "." + 
StringUtils.lowerCamelToLowerUnderscore(fieldName));
-        }
       }
       boolean remoteOnly = false;
       if (descriptor == null) {
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java 
b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java
index a5fb05147..d7abc0d58 100644
--- a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java
+++ b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java
@@ -75,8 +75,7 @@ class TypeDefEncoder {
         resolver, type, buildFieldsInfoFromDescriptors(resolver, type, 
descriptors));
   }
 
-  private static List<Descriptor> dropShadowedXlangNameFields(
-      Class<?> type, List<Descriptor> descriptors) {
+  static List<Descriptor> dropShadowedXlangNameFields(Class<?> type, 
List<Descriptor> descriptors) {
     List<Descriptor> result = new ArrayList<>(descriptors.size());
     Map<String, Integer> nameFieldIndex = new HashMap<>();
     for (Descriptor descriptor : descriptors) {
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/xlang/MetaShareXlangTest.java 
b/java/fory-core/src/test/java/org/apache/fory/xlang/MetaShareXlangTest.java
index 70c4e664d..966b2cc0d 100644
--- a/java/fory-core/src/test/java/org/apache/fory/xlang/MetaShareXlangTest.java
+++ b/java/fory-core/src/test/java/org/apache/fory/xlang/MetaShareXlangTest.java
@@ -23,11 +23,14 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertThrows;
 import static org.testng.Assert.assertTrue;
 
+import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import lombok.Data;
 import org.apache.fory.Fory;
 import org.apache.fory.ForyTestBase;
@@ -119,6 +122,25 @@ public class MetaShareXlangTest extends ForyTestBase {
     Set<int[]> values;
   }
 
+  abstract static class InheritedFieldParent {
+    public Map<String, BigDecimal> values = new ConcurrentHashMap<>();
+  }
+
+  static class InheritedFieldChild extends InheritedFieldParent {}
+
+  @Test
+  public void testInheritedField() {
+    for (boolean codegen : new boolean[] {false, true}) {
+      Fory fory = compatibleFory(InheritedFieldChild.class, codegen);
+      InheritedFieldChild value = new InheritedFieldChild();
+      value.values.put("one", BigDecimal.ONE);
+
+      InheritedFieldChild decoded = (InheritedFieldChild) 
fory.deserialize(fory.serialize(value));
+
+      assertEquals(decoded.values, value.values);
+    }
+  }
+
   @Test
   public void testTopLevelListArrayCompatibleRead() {
     Fory listFory = compatibleFory(DirectListField.class);


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

Reply via email to