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 42dc11518 feat(java): support deserialize not registered/exsited
class/fields for xlang compatible mode (#2655)
42dc11518 is described below
commit 42dc115188c3d2843a069d2a860904f4d6b628b3
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Sep 24 18:18:34 2025 +0800
feat(java): support deserialize not registered/exsited class/fields for
xlang compatible mode (#2655)
<!--
**Thanks for contributing to Apache Fory™.**
**If this is your first time opening a PR on fory, you can refer to
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).**
Contribution Checklist
- The **Apache Fory™** community has requirements on the naming of pr
titles. You can also find instructions in
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).
- Apache Fory™ 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.
-->
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
<!-- Describe the details of this PR. -->
## Related issues
Closes #2651
## 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.
-->
---
.../org/apache/fory/resolver/TypeResolver.java | 4 ++-
.../org/apache/fory/resolver/XtypeResolver.java | 17 ++++++++++
.../serializer/NonexistentClassSerializers.java | 22 +++++++++++--
.../java/org/apache/fory/CrossLanguageTest.java | 36 ++++++++++++++++++++++
4 files changed, 76 insertions(+), 3 deletions(-)
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 7c5bf9985..564aa0666 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
@@ -254,7 +254,9 @@ public abstract class TypeResolver {
classInfo.setSerializer(this, new NonexistentClassSerializer(fory,
classDef));
// ensure `NonexistentMetaSharedClass` registered to write
fixed-length class def,
// so we can rewrite it in `NonexistentClassSerializer`.
- Preconditions.checkNotNull(classId);
+ if (!fory.isCrossLanguage()) {
+ Preconditions.checkNotNull(classId);
+ }
} else {
classInfo.serializer =
NonexistentClassSerializers.getSerializer(fory,
classDef.getClassName(), cls);
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 e5a49743c..599a865c5 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
@@ -73,7 +73,9 @@ import org.apache.fory.serializer.ArraySerializers;
import
org.apache.fory.serializer.DeferedLazySerializer.DeferedLazyObjectSerializer;
import org.apache.fory.serializer.EnumSerializer;
import org.apache.fory.serializer.NonexistentClass;
+import org.apache.fory.serializer.NonexistentClass.NonexistentMetaShared;
import org.apache.fory.serializer.NonexistentClassSerializers;
+import
org.apache.fory.serializer.NonexistentClassSerializers.NonexistentClassSerializer;
import org.apache.fory.serializer.ObjectSerializer;
import org.apache.fory.serializer.SerializationUtils;
import org.apache.fory.serializer.Serializer;
@@ -140,6 +142,11 @@ public class XtypeResolver extends TypeResolver {
@Override
public void initialize() {
registerDefaultTypes();
+ if (shareMeta) {
+ Serializer serializer = new NonexistentClassSerializer(fory, null);
+ register(
+ NonexistentMetaShared.class, serializer, "", "unknown_struct",
Types.COMPATIBLE_STRUCT);
+ }
}
public void register(Class<?> type) {
@@ -513,6 +520,13 @@ public class XtypeResolver extends TypeResolver {
}
}
xtypeId = Types.MAP;
+ } else if (NonexistentClass.class.isAssignableFrom(cls)) {
+ serializer = NonexistentClassSerializers.getSerializer(fory, "Unknown",
cls);
+ if (cls.isEnum()) {
+ xtypeId = Types.ENUM;
+ } else {
+ xtypeId = shareMeta ? Types.COMPATIBLE_STRUCT : Types.STRUCT;
+ }
} else {
Class<Enum> enclosingClass = (Class<Enum>) cls.getEnclosingClass();
if (enclosingClass != null && enclosingClass.isEnum()) {
@@ -880,6 +894,9 @@ public class XtypeResolver extends TypeResolver {
if (fory.getXtypeResolver().isRegistered(cls)) {
return fory.getXtypeResolver().getClassInfo(cls).getXtypeId();
} else {
+ if (cls.isEnum()) {
+ return Types.ENUM;
+ }
if (ReflectionUtils.isMonomorphic(cls)) {
throw new UnsupportedOperationException(cls + " is not supported for
xlang serialization");
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/NonexistentClassSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/NonexistentClassSerializers.java
index 70d4d1cad..2adfe97dc 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/NonexistentClassSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/NonexistentClassSerializers.java
@@ -40,6 +40,7 @@ import org.apache.fory.resolver.MetaStringResolver;
import org.apache.fory.resolver.RefResolver;
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.NonexistentClass.NonexistentEnum;
+import
org.apache.fory.serializer.Serializers.CrossLanguageCompatibleSerializer;
import org.apache.fory.type.Descriptor;
import org.apache.fory.type.DescriptorGrouper;
import org.apache.fory.type.Generics;
@@ -227,9 +228,20 @@ public final class NonexistentClassSerializers {
obj.setEntries(entries);
return obj;
}
+
+ @Override
+ public void xwrite(MemoryBuffer buffer, Object value) {
+ write(buffer, value);
+ }
+
+ @Override
+ public Object xread(MemoryBuffer buffer) {
+ return read(buffer);
+ }
}
- public static final class NonexistentEnumClassSerializer extends Serializer {
+ public static final class NonexistentEnumClassSerializer
+ extends CrossLanguageCompatibleSerializer {
private final NonexistentEnum[] enumConstants;
private final MetaStringResolver metaStringResolver;
@@ -239,6 +251,12 @@ public final class NonexistentClassSerializers {
enumConstants = NonexistentEnum.class.getEnumConstants();
}
+ @Override
+ public void write(MemoryBuffer buffer, Object value) {
+ NonexistentEnum enumValue = (NonexistentEnum) value;
+ buffer.writeVarUint32Small7(enumValue.ordinal());
+ }
+
@Override
public Object read(MemoryBuffer buffer) {
if (fory.getConfig().serializeEnumByName()) {
@@ -248,7 +266,7 @@ public final class NonexistentClassSerializers {
int ordinal = buffer.readVarUint32Small7();
if (ordinal >= enumConstants.length) {
- ordinal = enumConstants.length - 1;
+ return NonexistentEnum.UNKNOWN;
}
return enumConstants[ordinal];
}
diff --git
a/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java
b/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java
index ea33695e9..d2397a50f 100644
--- a/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java
+++ b/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java
@@ -52,6 +52,7 @@ import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import lombok.Data;
@@ -66,6 +67,7 @@ import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.ArraySerializersTest;
import org.apache.fory.serializer.BufferObject;
import org.apache.fory.serializer.EnumSerializerTest;
+import org.apache.fory.serializer.NonexistentClass.NonexistentMetaShared;
import org.apache.fory.serializer.ObjectSerializer;
import org.apache.fory.serializer.Serializer;
import org.apache.fory.test.TestUtils;
@@ -906,6 +908,40 @@ public class CrossLanguageTest extends ForyTestBase {
structRoundBack(fory, a, "test_enum_field_register_by_id" + (compatible ?
"_compatible" : ""));
}
+ static class EnumFieldStruct2 {}
+
+ @Test(dataProvider = "enableCodegen")
+ public void testMissingEnumField(boolean enableCodegen) {
+ Supplier<Fory> builder =
+ () ->
+ Fory.builder()
+ .withLanguage(Language.XLANG)
+ .withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .withCodegen(enableCodegen)
+ .build();
+ Fory fory = builder.get();
+ fory.register(EnumTestClass.class, "test_enum");
+ fory.register(EnumFieldStruct.class, 2);
+
+ EnumFieldStruct a = new EnumFieldStruct();
+ a.f1 = EnumTestClass.FOO;
+ a.f2 = EnumTestClass.BAR;
+ a.f3 = "abc";
+
+ {
+ Fory fory2 = builder.get();
+ fory2.register(EnumTestClass.class, "test_enum");
+ fory2.register(EnumFieldStruct2.class, 2);
+ Assert.assertEquals(fory2.deserialize(fory.serialize(a)).getClass(),
EnumFieldStruct2.class);
+ }
+ {
+ Fory fory2 = builder.get();
+ fory2.register(EnumTestClass.class, "test_enum");
+ Assert.assertEquals(
+ fory2.deserialize(fory.serialize(a)).getClass(),
NonexistentMetaShared.class);
+ }
+ }
+
@Test
public void testCrossLanguageMetaShare() throws Exception {
Fory fory =
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]