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 c108cae67 fix(java): stabilize readResolve type metadata (#3831)
c108cae67 is described below
commit c108cae675421a06c4382cbec8f6f88bec8c55e2
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Jul 9 15:26:32 2026 +0530
fix(java): stabilize readResolve type metadata (#3831)
## Why?
## What does this PR do?
## Related issues
Closes #3828
## 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
---
.../org/apache/fory/resolver/ClassResolver.java | 4 +
.../apache/fory/resolver/ClassResolverTest.java | 132 +++++++++++++++++++++
2 files changed, 136 insertions(+)
diff --git
a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
index e5a144707..a1accbc36 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
@@ -754,6 +754,10 @@ public class ClassResolver extends TypeResolver {
return Types.ENUM;
} else if (serializer != null && !isStructSerializer(serializer)) {
return Types.EXT;
+ } else if (serializer == null && usesNonStructTypeDef(cls)) {
+ // Registered TypeInfo may be created before the natural serializer is
materialized. Keep
+ // TypeDef classification stable for classes that are known to use
non-struct serializers.
+ return Types.EXT;
} else {
return useStructEvolution(cls, metaContextShareEnabled)
? Types.COMPATIBLE_STRUCT
diff --git
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
index 5f5a17fc5..b98d6d95c 100644
---
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
@@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.Primitives;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
+import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
@@ -42,6 +43,8 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ArrayBlockingQueue;
@@ -1404,6 +1407,135 @@ public class ClassResolverTest extends ForyTestBase {
Assert.assertEquals(result[1].getValue(), 2);
}
+ @Test
+ public void testReadResolveTypeDefState() {
+ byte[] groupBytes =
+ newReadResolveFory()
+ .serialize(
+ new ReadResolveGroup(7, new
HashSet<>(Arrays.asList(ReadResolveCode.of("FR")))));
+ byte[] geoBytes =
+ newReadResolveFory()
+ .serialize(
+ new ReadResolveGeo(new
ArrayList<>(Arrays.asList(ReadResolveCode.of("GB")))));
+
+ Fory reader = newReadResolveFory();
+ ClassResolver resolver = (ClassResolver) reader.getTypeResolver();
+ assertEquals(resolver.getTypeIdForTypeDef(ReadResolveCode.class),
Types.EXT);
+ assertEquals(
+ reader.deserialize(groupBytes),
+ new ReadResolveGroup(7, new
HashSet<>(Arrays.asList(ReadResolveCode.of("FR")))));
+ assertEquals(resolver.getTypeIdForTypeDef(ReadResolveCode.class),
Types.EXT);
+ assertEquals(
+ reader.deserialize(geoBytes),
+ new ReadResolveGeo(new
ArrayList<>(Arrays.asList(ReadResolveCode.of("GB")))));
+ assertEquals(resolver.getTypeIdForTypeDef(ReadResolveCode.class),
Types.EXT);
+ }
+
+ private static Fory newReadResolveFory() {
+ Fory fory =
+ Fory.builder()
+ .withXlang(false)
+ .withRefTracking(true)
+ .requireClassRegistration(true)
+ .withCompatible(true)
+ .build();
+ fory.register(ReadResolveCode.class, 100);
+ fory.register(ReadResolveGroup.class, 101);
+ fory.register(ReadResolveGeo.class, 102);
+ return fory;
+ }
+
+ public static final class ReadResolveCode implements Serializable {
+ public String value;
+
+ public ReadResolveCode() {}
+
+ private ReadResolveCode(String value) {
+ this.value = value;
+ }
+
+ static ReadResolveCode of(String value) {
+ return new ReadResolveCode(value);
+ }
+
+ private Object readResolve() {
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ReadResolveCode)) {
+ return false;
+ }
+ ReadResolveCode that = (ReadResolveCode) o;
+ return Objects.equals(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(value);
+ }
+ }
+
+ public static final class ReadResolveGroup implements Serializable {
+ public int id;
+ public Set<ReadResolveCode> codes;
+
+ public ReadResolveGroup() {}
+
+ ReadResolveGroup(int id, Set<ReadResolveCode> codes) {
+ this.id = id;
+ this.codes = codes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ReadResolveGroup)) {
+ return false;
+ }
+ ReadResolveGroup that = (ReadResolveGroup) o;
+ return id == that.id && Objects.equals(codes, that.codes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, codes);
+ }
+ }
+
+ public static final class ReadResolveGeo implements Serializable {
+ public List<ReadResolveCode> codes;
+
+ public ReadResolveGeo() {}
+
+ ReadResolveGeo(List<ReadResolveCode> codes) {
+ this.codes = codes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ReadResolveGeo)) {
+ return false;
+ }
+ ReadResolveGeo that = (ReadResolveGeo) o;
+ return Objects.equals(codes, that.codes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(codes);
+ }
+ }
+
private static String captureOutput(Runnable action) throws Exception {
int previousLogLevel = LoggerFactory.getLogLevel();
PrintStream previousOut = System.out;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]