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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3e0641a322 CTR Fix ClassCastException when numeric request fields are 
deserialized as Integer
3e0641a322 is described below

commit 3e0641a322d402a0a32c9e1be068e054b7f184a4
Author: Cole Greer <[email protected]>
AuthorDate: Fri May 1 17:35:58 2026 -0700

    CTR Fix ClassCastException when numeric request fields are deserialized as 
Integer
    
    Clients like gremlin-javascript serialize INT32-range values (e.g.
    timeoutMs=5000) as GraphBinary INT (4 bytes), which deserializes to a
    Java Integer. The direct (long) and (int) casts on boxed Integer/Long
    threw ClassCastException, returning a 400 Bad Request.
    
    Cast through Number instead so both Integer and Long inputs are handled
    in RequestMessageSerializer (GraphBinary) and
    AbstractGraphSONMessageSerializerV4 (GraphSON).
---
 .../test/integration/traversal-test.js             |  2 +-
 .../ser/AbstractGraphSONMessageSerializerV4.java   |  2 +-
 .../util/ser/binary/RequestMessageSerializer.java  |  4 +--
 .../util/ser/binary/MessageSerializerTest.java     | 37 ++++++++++++++++++++++
 4 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/gremlin-js/gremlin-javascript/test/integration/traversal-test.js 
b/gremlin-js/gremlin-javascript/test/integration/traversal-test.js
index f543d70a49..1ada7cabff 100644
--- a/gremlin-js/gremlin-javascript/test/integration/traversal-test.js
+++ b/gremlin-js/gremlin-javascript/test/integration/traversal-test.js
@@ -303,7 +303,7 @@ describe('Traversal', function () {
     });
     it('should allow with_(evaluationTimeout,10)', function() {
       const g = 
anon.traversal().with_(connection).with_('x').with_('evaluationTimeout', 10);
-      return g.V().repeat(__.both()).iterate().then(() => assert.fail("should 
have tanked"), (err) => assert.strictEqual(err.statusCode, 400));
+      return g.V().repeat(__.both()).iterate().then(() => assert.fail("should 
have tanked"), (err) => assert.strictEqual(err.statusCode, 500));
     });
     it('should allow SeedStrategy', function () {
       const g = anon.traversal().with_(connection).withStrategies(new 
SeedStrategy({seed: 999999}));
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
index caa3def020..4fe1be6b72 100644
--- 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
+++ 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
@@ -333,7 +333,7 @@ public abstract class AbstractGraphSONMessageSerializerV4 
extends AbstractMessag
                 
builder.addMaterializeProperties(data.get(Tokens.ARGS_MATERIALIZE_PROPERTIES).toString());
             }
             if (data.containsKey(Tokens.ARGS_BATCH_SIZE)) {
-                builder.addChunkSize((int) data.get(Tokens.ARGS_BATCH_SIZE));
+                builder.addChunkSize(((Number) 
data.get(Tokens.ARGS_BATCH_SIZE)).intValue());
             }
             if (data.containsKey(Tokens.BULK_RESULTS)) {
                 
builder.addBulkResults(Boolean.parseBoolean(data.get(Tokens.BULK_RESULTS).toString()));
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java
 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java
index 9397e5afde..25cc6ab82d 100644
--- 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java
+++ 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/binary/RequestMessageSerializer.java
@@ -62,13 +62,13 @@ public class RequestMessageSerializer {
                 builder.addBindings((Map<String, Object>) 
fields.get(SerTokens.TOKEN_BINDINGS));
             }
             if (fields.containsKey(Tokens.TIMEOUT_MS)) {
-                builder.addTimeoutMillis((long) fields.get(Tokens.TIMEOUT_MS));
+                builder.addTimeoutMillis(((Number) 
fields.get(Tokens.TIMEOUT_MS)).longValue());
             }
             if (fields.containsKey(Tokens.ARGS_MATERIALIZE_PROPERTIES)) {
                 
builder.addMaterializeProperties(fields.get(Tokens.ARGS_MATERIALIZE_PROPERTIES).toString());
             }
             if (fields.containsKey(Tokens.ARGS_BATCH_SIZE)) {
-                builder.addChunkSize((int) fields.get(Tokens.ARGS_BATCH_SIZE));
+                builder.addChunkSize(((Number) 
fields.get(Tokens.ARGS_BATCH_SIZE)).intValue());
             }
             if (fields.containsKey(Tokens.BULK_RESULTS)) {
                 
builder.addBulkResults(Boolean.parseBoolean(fields.get(Tokens.BULK_RESULTS).toString()));
diff --git 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java
 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java
index 6dfe98c0db..48fa31aa27 100644
--- 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java
+++ 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/MessageSerializerTest.java
@@ -24,18 +24,23 @@ import io.netty.handler.codec.http.HttpResponseStatus;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
+import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
 import org.apache.tinkerpop.gremlin.util.MessageSerializer;
 import org.apache.tinkerpop.gremlin.util.Tokens;
 import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.util.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4;
 import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV4;
+import org.apache.tinkerpop.gremlin.util.ser.NettyBufferFactory;
 import org.apache.tinkerpop.gremlin.util.ser.SerializationException;
+import org.apache.tinkerpop.gremlin.util.ser.SerTokens;
 import org.apache.tinkerpop.gremlin.util.ser.Serializers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -142,6 +147,38 @@ public class MessageSerializerTest {
         assertResponseEquals(response, deserialized);
     }
 
+    @Test
+    public void shouldDeserializeRequestWithIntegerNumericFields() throws 
SerializationException, IOException {
+        // Simulates what happens when a client (e.g., JavaScript) serializes 
timeoutMs and batchSize
+        // as GraphBinary INT (4 bytes) instead of LONG/INT. The server must 
handle both numeric widths.
+        final GraphBinaryWriter writer = new GraphBinaryWriter();
+        final GraphBinaryReader reader = new GraphBinaryReader();
+        final NettyBufferFactory bufferFactory = new NettyBufferFactory();
+        final RequestMessageSerializer requestSerializer = new 
RequestMessageSerializer();
+
+        // Build a fields map with Integer values (as a JS client would 
produce for INT32-range values)
+        final Map<String, Object> fields = new HashMap<>();
+        fields.put(SerTokens.TOKEN_LANGUAGE, "gremlin-lang");
+        fields.put(Tokens.TIMEOUT_MS, 5000);          // Integer, not Long
+        fields.put(Tokens.ARGS_BATCH_SIZE, 64);        // Integer, not Long 
(though normally int)
+
+        final String gremlin = "g.V()";
+
+        // Manually write the GraphBinary request buffer with Integer-typed 
numeric fields
+        final ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
+        final org.apache.tinkerpop.gremlin.structure.io.Buffer buffer = 
bufferFactory.create(byteBuf);
+        buffer.writeByte(GraphBinaryWriter.VERSION_BYTE);
+        writer.writeValue(fields, buffer, false);
+        writer.writeValue(gremlin, buffer, false);
+
+        final RequestMessage deserialized = 
requestSerializer.readValue(byteBuf, reader);
+        assertEquals(5000L, (long) deserialized.getField(Tokens.TIMEOUT_MS));
+        assertEquals(64, (int) deserialized.getField(Tokens.ARGS_BATCH_SIZE));
+        assertEquals(gremlin, deserialized.getGremlin());
+
+        byteBuf.release();
+    }
+
     private static void assertResponseEquals(ResponseMessage expected, 
ResponseMessage actual) {
         // Status
         assertEquals(expected.getStatus().getCode(), 
actual.getStatus().getCode());

Reply via email to