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); } }
