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 9a12400ee fix(java): Fix CopyOnWriteArrayList field serialization
(#3079)
9a12400ee is described below
commit 9a12400eeadb7ebc2d1ea3a132e77fec7f4768a9
Author: Vybhav Jayasankar <[email protected]>
AuthorDate: Tue Dec 23 21:49:09 2025 +0530
fix(java): Fix CopyOnWriteArrayList field serialization (#3079)
## Why?
Fory doesn't currently support serialization of any object that has a
`CopyOnWriteArrayList` field with codegen, because the generated code
attempts to cast `CollectionSnapshot` to `List`, throwing the following
exception :
```
org.apache.fory.exception.SerializationException:
java.lang.ClassCastException:
class org.apache.fory.collection.CollectionSnapshot cannot be cast to class
java.util.List
(org.apache.fory.collection.CollectionSnapshot is in unnamed module of
loader 'app';
java.util.List is in module java.base of loader 'bootstrap')
( . . . )
org.apache.fory.serializer.collection.CollectionSerializersTest.testCopyOnWriteArrayListNested(CollectionSerializersTest.java:407)
Caused by: java.lang.ClassCastException: class
org.apache.fory.collection.CollectionSnapshot cannot be cast to class
java.util.List
(org.apache.fory.collection.CollectionSnapshot is in unnamed module of
loader 'app';
java.util.List is in module java.base of loader 'bootstrap')
at
org.apache.fory.serializer.collection.CollectionSerializersTest_NestedCopyOnWriteArrayListForyCodec_0.writeFields$(CollectionSerializersTest_NestedCopyOnWriteArrayListForyCodec_0.java:63)
at
org.apache.fory.serializer.collection.CollectionSerializersTest_NestedCopyOnWriteArrayListForyCodec_0.write(CollectionSerializersTest_NestedCopyOnWriteArrayListForyCodec_0.java:130)
```
This is the relevant code from the generated codec that attempts the
invalid class cast.
```
CollectionLikeSerializer collectionLikeSerializer =
this.writeCollectionClassInfo(list0, memoryBuffer1);
if (collectionLikeSerializer.supportCodegenHook()) {
java.util.List list1 =
(java.util.List)collectionLikeSerializer.onCollectionWrite(memoryBuffer1,
list0);
```
## What does this PR do?
* feat: Update `CollectionSnapshot` to extend `AbstractList` instead of
`AbstractCollection`, and implement `get(index)` method
* test: Add test in `CollectionSerializersTest` for serializing objects
with CopyOnWriteArrayList fields
* test: Add test in `CollectionSnapshotTest` for
`CollectionSnapshot.get(index)`
## Related issues
Fixes pending issues from #2918.
## 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
---
.../apache/fory/collection/CollectionSnapshot.java | 9 +++++--
.../fory/collection/CollectionSnapshotTest.java | 30 ++++++++++++++++++++++
.../collection/CollectionSerializersTest.java | 18 +++++++++++++
3 files changed, 55 insertions(+), 2 deletions(-)
diff --git
a/java/fory-core/src/main/java/org/apache/fory/collection/CollectionSnapshot.java
b/java/fory-core/src/main/java/org/apache/fory/collection/CollectionSnapshot.java
index 4f15a909c..de8aae70c 100644
---
a/java/fory-core/src/main/java/org/apache/fory/collection/CollectionSnapshot.java
+++
b/java/fory-core/src/main/java/org/apache/fory/collection/CollectionSnapshot.java
@@ -19,7 +19,7 @@
package org.apache.fory.collection;
-import java.util.AbstractCollection;
+import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import org.apache.fory.annotation.Internal;
@@ -46,7 +46,7 @@ import org.apache.fory.annotation.Internal;
* @since 1.0
*/
@Internal
-public class CollectionSnapshot<E> extends AbstractCollection<E> {
+public class CollectionSnapshot<E> extends AbstractList<E> {
/** Threshold for array reallocation during clear operation to prevent
memory leaks. */
private static final int CLEAR_ARRAY_SIZE_THRESHOLD = 2048;
@@ -79,6 +79,11 @@ public class CollectionSnapshot<E> extends
AbstractCollection<E> {
return size;
}
+ @Override
+ public E get(int index) {
+ return array.get(index);
+ }
+
/**
* Returns an iterator over the elements in this collection. The iterator is
designed for
* single-pass iteration and maintains its position through a shared index.
diff --git
a/java/fory-core/src/test/java/org/apache/fory/collection/CollectionSnapshotTest.java
b/java/fory-core/src/test/java/org/apache/fory/collection/CollectionSnapshotTest.java
index e0e05bd6b..de1c536de 100644
---
a/java/fory-core/src/test/java/org/apache/fory/collection/CollectionSnapshotTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/collection/CollectionSnapshotTest.java
@@ -107,4 +107,34 @@ public class CollectionSnapshotTest {
assertEquals(result, newData);
}
}
+
+ @Test
+ public void testGet() {
+ CollectionSnapshot<String> snapshot = new CollectionSnapshot<>();
+ List<String> source = Arrays.asList("a", "b", "c");
+ snapshot.setCollection(source);
+
+ assertEquals(snapshot.get(0), "a");
+ assertEquals(snapshot.get(1), "b");
+ assertEquals(snapshot.get(2), "c");
+ }
+
+ @Test
+ public void testIndexedAccessAfterReuse() {
+ CollectionSnapshot<String> snapshot = new CollectionSnapshot<>();
+
+ // First use
+ snapshot.setCollection(Arrays.asList("a", "b", "c"));
+ assertEquals(snapshot.get(0), "a");
+ assertEquals(snapshot.get(1), "b");
+ assertEquals(snapshot.get(2), "c");
+
+ snapshot.clear();
+
+ // Second use
+ snapshot.setCollection(Arrays.asList("x", "y"));
+ assertEquals(snapshot.get(0), "x");
+ assertEquals(snapshot.get(1), "y");
+ assertEquals(snapshot.size(), 2);
+ }
}
diff --git
a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java
b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java
index 59f12386f..607f1087a 100644
---
a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java
@@ -62,6 +62,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.LongStream;
import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import org.apache.fory.Fory;
import org.apache.fory.ForyTestBase;
import org.apache.fory.config.Language;
@@ -389,6 +390,23 @@ public class CollectionSerializersTest extends
ForyTestBase {
CollectionSerializers.CopyOnWriteArrayListSerializer.class);
}
+ @EqualsAndHashCode
+ public static class NestedCopyOnWriteArrayList {
+ private final CopyOnWriteArrayList<String> list;
+
+ public NestedCopyOnWriteArrayList(CopyOnWriteArrayList<String> list) {
+ this.list = list;
+ }
+ }
+
+ @Test
+ public void testCopyOnWriteArrayListNested() {
+ final CopyOnWriteArrayList<String> list =
+ new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c"));
+ NestedCopyOnWriteArrayList nestedObject = new
NestedCopyOnWriteArrayList(list);
+ Assert.assertEquals(nestedObject, serDe(getJavaFory(), nestedObject));
+ }
+
@Test(dataProvider = "foryCopyConfig")
public void testCopyOnWriteArrayList(Fory fory) {
final CopyOnWriteArrayList<Object> list =
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]