This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch test-run
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 4a5e372991ee0660e534fd7671276ac08796c93d
Author: Cole Greer <[email protected]>
AuthorDate: Wed Jul 8 22:26:53 2026 -0700

    CTR: Register scala.collection.mutable.ArraySeq.ofRef in Spark Gryo 
serializers
    
    Adds a defensive registration for scala.collection.mutable.ArraySeq.ofRef
    alongside the existing immutable.ArraySeq.ofRef registration in
    GryoRegistrator and GryoSerializer. mutable.ArraySeq is the type that the
    deprecated scala.collection.mutable.WrappedArray alias resolves to under
    Scala 2.13, so this guards against a mismatched Spark/Scala build on the
    classpath at runtime producing that variant instead of the immutable one
    Spark 4/Scala 2.13 normally produces.
    
    WrappedArraySerializer is generalized to serialize/deserialize against
    scala.collection.Seq, with IMMUTABLE and MUTABLE static instances backing
    each concrete .ofRef registration.
    
    Assisted-by: Kiro:claude-sonnet-4.5
---
 .../spark/structure/io/gryo/GryoRegistrator.java   |  4 ++
 .../spark/structure/io/gryo/GryoSerializer.java    |  6 ++-
 .../structure/io/gryo/WrappedArraySerializer.java  | 54 ++++++++++++++++++----
 3 files changed, 54 insertions(+), 10 deletions(-)

diff --git 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
index 705d883a73..014d35e4b3 100644
--- 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
+++ 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoRegistrator.java
@@ -207,6 +207,10 @@ public class GryoRegistrator implements KryoRegistrator {
             throw new IllegalStateException(e.getMessage(), e);
         }
         m.put(ArraySeq.ofRef.class, null);
+        // defensive registration: scala.collection.mutable.ArraySeq.ofRef is 
what the deprecated
+        // scala.collection.mutable.WrappedArray alias resolves to under Scala 
2.13 -- register it in case a
+        // mismatched Spark/Scala build on the classpath at runtime produces 
it instead of the immutable variant
+        m.put(scala.collection.mutable.ArraySeq.ofRef.class, null);
         m.put(MessagePayload.class, null);
         m.put(ViewIncomingPayload.class, null);
         m.put(ViewOutgoingPayload.class, null);
diff --git 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
index 35f631703d..de90ae2a69 100644
--- 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
+++ 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/GryoSerializer.java
@@ -147,7 +147,11 @@ public final class GryoSerializer extends Serializer 
implements Serializable {
                 super.register(GryoIo.class, Class.forName("scala.None$"), new 
JavaSerializer());
                 super.register(GryoIo.class, Class.forName("scala.Some$"), new 
JavaSerializer());
                 super.register(GryoIo.class, Class.forName("scala.Some"), new 
JavaSerializer());
-                super.register(GryoIo.class, ArraySeq.ofRef.class, new 
WrappedArraySerializer());
+                super.register(GryoIo.class, ArraySeq.ofRef.class, 
WrappedArraySerializer.IMMUTABLE);
+                // defensive registration: 
scala.collection.mutable.ArraySeq.ofRef is what the deprecated
+                // scala.collection.mutable.WrappedArray alias resolves to 
under Scala 2.13 -- register it in case a
+                // mismatched Spark/Scala build on the classpath at runtime 
produces it instead of the immutable variant
+                super.register(GryoIo.class, 
scala.collection.mutable.ArraySeq.ofRef.class, WrappedArraySerializer.MUTABLE);
                 super.register(GryoIo.class, MessagePayload.class, null);
                 super.register(GryoIo.class, ViewIncomingPayload.class, null);
                 super.register(GryoIo.class, ViewOutgoingPayload.class, null);
diff --git 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/WrappedArraySerializer.java
 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/WrappedArraySerializer.java
index 8d6be792f2..179d8421e4 100644
--- 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/WrappedArraySerializer.java
+++ 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/structure/io/gryo/WrappedArraySerializer.java
@@ -23,19 +23,55 @@ import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.apache.tinkerpop.shaded.kryo.Serializer;
 import org.apache.tinkerpop.shaded.kryo.io.Input;
 import org.apache.tinkerpop.shaded.kryo.io.Output;
+import scala.collection.Seq;
 import scala.collection.immutable.ArraySeq;
 
+import java.util.function.Function;
+
 /**
- * Serializer for Scala's immutable {@link ArraySeq}. In Scala 2.13 (the Scala 
version Spark is built against) wrapping
- * a reference array produces an {@code immutable.ArraySeq.ofRef}, which 
replaced the {@code WrappedArray} used under
- * Scala 2.12.
+ * Serializer for Scala's reference-array wrapper sequences. In Scala 2.13 
(the Scala version Spark is built against)
+ * wrapping a reference array produces an {@code immutable.ArraySeq.ofRef}, 
which replaced the {@code WrappedArray}
+ * used under Scala 2.12. Scala 2.13 also retains {@code mutable.ArraySeq} as 
a distinct type -- it is what the
+ * deprecated {@code scala.collection.mutable.WrappedArray} type/val alias 
resolves to. Both variants share the same
+ * {@code apply(int)}/{@code size()} shape via {@link Seq}, so a single 
implementation is reused for both, exposed as
+ * two instances so each concrete {@code .ofRef} class can be registered with 
Kryo under its own type. This is
+ * defensive coverage in case a mismatched Spark/Scala build on the classpath 
at runtime produces the Scala
+ * 2.12-style mutable variant instead of the immutable one Spark 4/Scala 2.13 
normally produces.
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class WrappedArraySerializer<T> extends Serializer<ArraySeq<T>> {
+public final class WrappedArraySerializer<T> extends Serializer<Seq<T>> {
+
+    /**
+     * Serializer for {@code scala.collection.immutable.ArraySeq.ofRef} -- the 
type Spark 4/Scala 2.13 normally
+     * produces when wrapping a reference array.
+     */
+    public static final WrappedArraySerializer<Object> IMMUTABLE =
+            new WrappedArraySerializer<>(array -> new ArraySeq.ofRef<>(array));
+
+    /**
+     * Serializer for {@code scala.collection.mutable.ArraySeq.ofRef} -- the 
type that the deprecated
+     * {@code scala.collection.mutable.WrappedArray} alias resolves to.
+     */
+    public static final WrappedArraySerializer<Object> MUTABLE =
+            new WrappedArraySerializer<>(array -> new 
scala.collection.mutable.ArraySeq.ofRef<>(array));
+
+    private final Function<T[], Seq<T>> constructor;
+
+    /**
+     * No-arg constructor retained for backward compatibility (e.g. reflective 
instantiation). Defaults to producing
+     * {@code immutable.ArraySeq.ofRef} instances, matching this class's 
original behavior.
+     */
+    public WrappedArraySerializer() {
+        this(array -> new ArraySeq.ofRef<>(array));
+    }
+
+    private WrappedArraySerializer(final Function<T[], Seq<T>> constructor) {
+        this.constructor = constructor;
+    }
 
     @Override
-    public void write(final Kryo kryo, final Output output, final ArraySeq<T> 
iterable) {
+    public void write(final Kryo kryo, final Output output, final Seq<T> 
iterable) {
         output.writeVarInt(iterable.size(), true);
         for (int i = 0; i < iterable.size(); i++) {
             kryo.writeClassAndObject(output, iterable.apply(i));
@@ -43,12 +79,12 @@ public final class WrappedArraySerializer<T> extends 
Serializer<ArraySeq<T>> {
     }
 
     @Override
-    public ArraySeq<T> read(final Kryo kryo, final Input input, final 
Class<ArraySeq<T>> aClass) {
+    public Seq<T> read(final Kryo kryo, final Input input, final Class<Seq<T>> 
aClass) {
         final int size = input.readVarInt(true);
-        final Object[] array = new Object[size];
+        final T[] array = (T[]) new Object[size];
         for (int i = 0; i < size; i++) {
-            array[i] = kryo.readClassAndObject(input);
+            array[i] = (T) kryo.readClassAndObject(input);
         }
-        return new ArraySeq.ofRef<>((T[]) array);
+        return this.constructor.apply(array);
     }
 }

Reply via email to