This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.7-dev by this push:
new 0c9b8bf759 TINKERPOP-3163 fixed CallStep serialization (#3140)
0c9b8bf759 is described below
commit 0c9b8bf75987c12a7ecb7a7a2dba4068a8d19303
Author: Valentyn Kahamlyk <[email protected]>
AuthorDate: Tue Jul 8 14:54:25 2025 -0700
TINKERPOP-3163 fixed CallStep serialization (#3140)
Fixed serialization of CallStep.
---
CHANGELOG.asciidoc | 1 +
.../process/traversal/step/map/CallStep.java | 22 +++----
.../process/traversal/step/map/CallStepTest.java | 68 ++++++++++++++++++++++
3 files changed, 81 insertions(+), 10 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 9735cb1de8..6287d06220 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -47,6 +47,7 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Changed `PythonTranslator` to generate snake case step naming instead of
camel case.
* Changed `gremlin-go` Client `ReadBufferSize` and `WriteBufferSize` defaults
to 1048576 (1MB) to align with DriverRemoteConnection.
* Fixed bug in `IndexStep` which prevented Java serialization due to
non-serializable lambda usage by creating serializable function classes.
+* Fixed bug in `CallStep` which prevented Java serialization due to
non-serializable `ServiceCallContext` and `Service` usage.
* Fixed bug in `Operator` which was caused only a single method parameter to
be Collection type checked instead of all parameters.
* Support hot reloading of SSL certificates.
* Added the `PopContaining` interface designed to get label and `Pop`
combinations held in a `PopInstruction` object.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
index 2435be373c..feb7f90b8d 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
@@ -59,10 +59,10 @@ public final class CallStep<S, E> extends AbstractStep<S,
E> implements Traversa
private final boolean isStart;
private boolean first = true;
- private ServiceCallContext ctx;
- private String serviceName;
- private Service<S, E> service;
- private Map staticParams;
+ private transient ServiceCallContext ctx;
+ private final String serviceName;
+ private transient Service<S, E> service;
+ private final Map staticParams;
private Traversal.Admin<S,Map> mapTraversal;
private Parameters parameters;
@@ -90,7 +90,6 @@ public final class CallStep<S, E> extends AbstractStep<S, E>
implements Traversa
this.staticParams = staticParams == null ? new LinkedHashMap() :
staticParams;
this.mapTraversal = mapTraversal == null ? null :
integrateChild(mapTraversal);
this.parameters = new Parameters();
- this.ctx = new ServiceCallContext(traversal, this);
}
protected Service<S, E> service() {
@@ -98,6 +97,10 @@ public final class CallStep<S, E> extends AbstractStep<S, E>
implements Traversa
return service != null ? service : (service =
getServiceRegistry().get(serviceName, isStart, staticParams));
}
+ private ServiceCallContext ctx() {
+ return ctx != null ? ctx : (ctx = new ServiceCallContext(traversal,
this));
+ }
+
public String getServiceName() {
return serviceName;
}
@@ -244,17 +247,17 @@ public final class CallStep<S, E> extends AbstractStep<S,
E> implements Traversa
protected CloseableIterator start() {
final Map params = getMergedParams();
- return service().execute(this.ctx, params);
+ return service().execute(this.ctx(), params);
}
protected CloseableIterator flatMap(final Traverser.Admin<S> traverser) {
final Map params = getMergedParams(traverser);
- return service().execute(this.ctx, traverser, params);
+ return service().execute(this.ctx(), traverser, params);
}
protected CloseableIterator flatMap(final TraverserSet<S> traverserSet) {
final Map params = getMergedParams(traverserSet);
- return service().execute(this.ctx, traverserSet, params);
+ return service().execute(this.ctx(), traverserSet, params);
}
protected ServiceRegistry getServiceRegistry() {
@@ -288,7 +291,7 @@ public final class CallStep<S, E> extends AbstractStep<S,
E> implements Traversa
if (mapTraversal != null)
this.integrateChild(mapTraversal);
parameters.getTraversals().forEach(this::integrateChild);
- ctx = new ServiceCallContext(parentTraversal, this);
+ ctx = null;
}
@Override
@@ -328,7 +331,6 @@ public final class CallStep<S, E> extends AbstractStep<S,
E> implements Traversa
final CallStep<S, E> clone = (CallStep<S, E>) super.clone();
clone.mapTraversal = mapTraversal != null ? mapTraversal.clone() :
null;
clone.parameters = parameters.clone();
- clone.ctx = new ServiceCallContext(traversal, clone);
clone.iterator = EmptyCloseableIterator.instance();
clone.head = null;
return clone;
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStepTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStepTest.java
new file mode 100644
index 0000000000..8309d7abcb
--- /dev/null
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStepTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
+import org.apache.tinkerpop.gremlin.structure.service.Service;
+import org.junit.Test;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CallStepTest {
+
+ @Test
+ public void testSerializationRoundTrip() {
+ final byte[] serialized =
SerializationUtils.serialize(__.call("--list"));
+ final DefaultTraversal<Object, Object> deserialized =
SerializationUtils.deserialize(serialized);
+
+ assertEquals(1, deserialized.getSteps().size());
+ assertTrue(deserialized.getSteps().get(0) instanceof CallStep);
+ assertEquals("--list", ((CallStep)
deserialized.getSteps().get(0)).getServiceName());
+ }
+
+ @Test
+ public void traversalReplacementTest() {
+ final Traversal.Admin a = __.inject("a").asAdmin();
+ final Traversal.Admin b = __.inject("b").asAdmin();
+
+ final CallStep step = new CallStep(a, false, "service");
+ assertEquals("a", getContextTraversalValue(step));
+ step.setTraversal(b);
+ assertEquals("b", getContextTraversalValue(step));
+ }
+
+ private Object getContextTraversalValue(final CallStep step) {
+ try {
+ final Method privateMethod =
CallStep.class.getDeclaredMethod("ctx");
+ privateMethod.setAccessible(true);
+ final Service.ServiceCallContext context =
(Service.ServiceCallContext) privateMethod.invoke(step);
+ return context.getTraversal().next();
+ } catch (final NoSuchMethodException | InvocationTargetException |
IllegalAccessException e) {
+ // This should never happen.
+ throw new RuntimeException("ctx() method in class CallStep is
renamed or removed. Please fix test.");
+ }
+ }
+}