You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by fl...@apache.org on 2020/12/04 11:11:33 UTC

[tinkerpop] branch TINKERPOP-2472 created (now 33be861)

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

florianhockmann pushed a change to branch TINKERPOP-2472
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


      at 33be861  TINKERPOP-2472 Decouple the driver from the IO format

This branch includes the following new commits:

     new 33be861  TINKERPOP-2472 Decouple the driver from the IO format

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[tinkerpop] 01/01: TINKERPOP-2472 Decouple the driver from the IO format

Posted by fl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

florianhockmann pushed a commit to branch TINKERPOP-2472
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 33be8617d025711d902594821f1ed47dedf84b18
Author: Florian Hockmann <fh...@florian-hockmann.de>
AuthorDate: Fri Dec 4 11:56:14 2020 +0100

    TINKERPOP-2472 Decouple the driver from the IO format
    
    It is now easier to use the driver with a serialization format that is
    not GraphSON or even JSON based. This should allow us to support
    GraphBinary.
    
    NOTE: The driver now always deserializes a result completely, e.g.,
    skipping serialization like it was implemented in TINKERPOP-2067 is no
    longer supported. However, users who need this functionality can simply
    implement their own IMessageSerializer with this functionality.
---
 CHANGELOG.asciidoc                                 |   1 +
 .../src/Gremlin.Net/Driver/Connection.cs           |  29 ++---
 .../src/Gremlin.Net/Driver/ConnectionFactory.cs    |  18 +--
 .../src/Gremlin.Net/Driver/GremlinClient.cs        | 122 +++++++++++++++++----
 .../src/Gremlin.Net/Driver/IMessageSerializer.cs   |  48 ++++++++
 .../Gremlin.Net/Driver/JsonMessageSerializer.cs    |  60 ----------
 .../Gremlin.Net/Driver/Messages/ResponseMessage.cs |  17 ++-
 .../Gremlin.Net/Driver/Messages/ResponseResult.cs  |  18 ++-
 .../Gremlin.Net/Driver/Messages/ResponseStatus.cs  |  18 ++-
 ...s => ResponseHandlerForSingleRequestMessage.cs} |  19 +---
 .../IO/GraphSON/GraphSON2MessageSerializer.cs      |  43 ++++++++
 .../IO/GraphSON/GraphSON3MessageSerializer.cs      |  43 ++++++++
 .../IO/GraphSON/GraphSONMessageSerializer.cs       | 100 +++++++++++++++++
 .../IO/SerializationTokens.cs}                     |  20 ++--
 .../Docs/Dev/Provider/IndexTests.cs                |   2 +-
 .../Docs/Reference/GremlinVariantsTests.cs         |   3 +-
 .../Driver/GremlinClientTests.cs                   |  26 -----
 ...rTests.cs => GraphSONMessageSerializerTests.cs} |  26 +++--
 .../Driver/GremlinClientTests.cs                   |  39 ++++++-
 .../IO/GraphSON/BytecodeGraphSONSerializerTests.cs |   3 +-
 20 files changed, 470 insertions(+), 185 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 1521246..595aa73 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ This release also includes changes from <<release-3-4-3, 3.4.3>>.
 * Ensured better consistency of the use of `null` as arguments to mutation steps.
 * Allowed `property(T.label,Object)` to be used if no value was supplied to `addV(String)`.
 * Allowed additional arguments to `Client.submit()` in Javascript driver to enable setting of parameters like `scriptEvaluationTimeout`.
+* Gremlin.Net driver no longer supports skipping deserialization by default. User can however create their own `IMessageSerializer` if they need this functionality.
 * Supported deserialization of `dict` as a key in a `dict` for Python.
 * Added a `Graph.Feature` for `supportsNullPropertyValues`.
 * Modified `TokenTraversal` to support `Property` thus `by(key)` and `by(value)` can now apply to `Edge` and meta-properties.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
index 9bc4658..0b55b6a 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
@@ -30,22 +30,19 @@ using System.Threading;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
 using Gremlin.Net.Process;
-using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
 {
     internal interface IResponseHandlerForSingleRequestMessage
     {
-        void HandleReceived(ResponseMessage received);
+        void HandleReceived(ResponseMessage<List<object>> received);
         void Finalize(Dictionary<string, object> statusAttributes);
         void HandleFailure(Exception objException);
     }
 
     internal class Connection : IConnection
     {
-        private readonly GraphSONReader _graphSONReader;
-        private readonly GraphSONWriter _graphSONWriter;
-        private readonly JsonMessageSerializer _messageSerializer;
+        private readonly IMessageSerializer _messageSerializer;
         private readonly Uri _uri;
         private readonly WebSocketConnection _webSocketConnection;
         private readonly string _username;
@@ -60,8 +57,7 @@ namespace Gremlin.Net.Driver
         private int _writeInProgress = 0;
         private const int Closed = 1;
 
-        public Connection(Uri uri, string username, string password, GraphSONReader graphSONReader,
-            GraphSONWriter graphSONWriter, string mimeType,
+        public Connection(Uri uri, string username, string password, IMessageSerializer messageSerializer,
             Action<ClientWebSocketOptions> webSocketConfiguration, string sessionId)
         {
             _uri = uri;
@@ -72,9 +68,7 @@ namespace Gremlin.Net.Driver
             {
                 _sessionEnabled = true;
             }
-            _graphSONReader = graphSONReader;
-            _graphSONWriter = graphSONWriter;
-            _messageSerializer = new JsonMessageSerializer(mimeType);
+            _messageSerializer = messageSerializer;
             _webSocketConnection = new WebSocketConnection(webSocketConfiguration);
         }
 
@@ -90,7 +84,7 @@ namespace Gremlin.Net.Driver
 
         public Task<ResultSet<T>> SubmitAsync<T>(RequestMessage requestMessage)
         {
-            var receiver = new ResponseHandlerForSingleRequestMessage<T>(_graphSONReader);
+            var receiver = new ResponseHandlerForSingleRequestMessage<T>();
             _callbackByRequestId.GetOrAdd(requestMessage.RequestId, receiver);
             _writeQueue.Enqueue(requestMessage);
             BeginSendingMessages();
@@ -111,7 +105,7 @@ namespace Gremlin.Net.Driver
                 try
                 {
                     var received = await _webSocketConnection.ReceiveMessageAsync().ConfigureAwait(false);
-                    Parse(received);
+                    HandleReceived(received);
                 }
                 catch (Exception e)
                 {
@@ -121,9 +115,9 @@ namespace Gremlin.Net.Driver
             }
         }
 
-        private void Parse(byte[] received)
+        private void HandleReceived(byte[] received)
         {
-            var receivedMsg = _messageSerializer.DeserializeMessage<ResponseMessage>(received);
+            var receivedMsg = _messageSerializer.DeserializeMessage(received);
             if (receivedMsg == null)
             {
                 ThrowMessageDeserializedNull();
@@ -131,7 +125,7 @@ namespace Gremlin.Net.Driver
 
             try
             {
-                TryParseResponseMessage(receivedMsg);
+                HandleReceivedMessage(receivedMsg);
             }
             catch (Exception e)
             {
@@ -145,7 +139,7 @@ namespace Gremlin.Net.Driver
         private static void ThrowMessageDeserializedNull() =>
             throw new InvalidOperationException("Received data deserialized into null object message. Cannot operate on it.");
 
-        private void TryParseResponseMessage(ResponseMessage receivedMsg)
+        private void HandleReceivedMessage(ResponseMessage<List<object>> receivedMsg)
         {
             var status = receivedMsg.Status;
             status.ThrowIfStatusIndicatesError();
@@ -246,8 +240,7 @@ namespace Gremlin.Net.Driver
             {
                 message = RebuildSessionMessage(message);
             }
-            var graphsonMsg = _graphSONWriter.WriteObject(message);
-            var serializedMsg = _messageSerializer.SerializeMessage(graphsonMsg);
+            var serializedMsg = _messageSerializer.SerializeMessage(message);
             await _webSocketConnection.SendMessageAsync(serializedMsg).ConfigureAwait(false);
         }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
index 9ef32a5..59807a1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionFactory.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -23,35 +23,29 @@
 
 using System;
 using System.Net.WebSockets;
-using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
 {
     internal class ConnectionFactory : IConnectionFactory
     {
-        private readonly GraphSONReader _graphSONReader;
-        private readonly GraphSONWriter _graphSONWriter;
         private readonly Action<ClientWebSocketOptions> _webSocketConfiguration;
         private readonly GremlinServer _gremlinServer;
-        private readonly string _mimeType;
         private readonly string _sessionId;
+        private IMessageSerializer _messageSerializer;
 
-        public ConnectionFactory(GremlinServer gremlinServer, GraphSONReader graphSONReader,
-            GraphSONWriter graphSONWriter, string mimeType,
+        public ConnectionFactory(GremlinServer gremlinServer, IMessageSerializer messageSerializer,
             Action<ClientWebSocketOptions> webSocketConfiguration, string sessionId)
         {
             _gremlinServer = gremlinServer;
-            _mimeType = mimeType;
+            _messageSerializer = messageSerializer;
             _sessionId = sessionId;
-            _graphSONReader = graphSONReader ?? throw new ArgumentNullException(nameof(graphSONReader));
-            _graphSONWriter = graphSONWriter ?? throw new ArgumentNullException(nameof(graphSONWriter));
             _webSocketConfiguration = webSocketConfiguration;
         }
 
         public IConnection CreateConnection()
         {
-            return new Connection(_gremlinServer.Uri, _gremlinServer.Username, _gremlinServer.Password, _graphSONReader,
-                                 _graphSONWriter, _mimeType, _webSocketConfiguration, _sessionId);
+            return new Connection(_gremlinServer.Uri, _gremlinServer.Username, _gremlinServer.Password,
+                _messageSerializer, _webSocketConfiguration, _sessionId);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
index bf637bf..745a3cc 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
@@ -22,10 +22,10 @@
 #endregion
 
 using System;
-using System.Collections.Generic;
 using System.Net.WebSockets;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
+using Gremlin.Net.Structure.IO;
 using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
@@ -35,18 +35,29 @@ namespace Gremlin.Net.Driver
     /// </summary>
     public class GremlinClient : IGremlinClient
     {
-        /// <summary>
-        /// Defines the default mime type to use.
-        /// </summary>
-        public const string DefaultMimeType = "application/vnd.gremlin-v3.0+json";
+        private readonly ConnectionPool _connectionPool;
 
         /// <summary>
-        /// The GraphSON2 mime type to use.
+        ///     Initializes a new instance of the <see cref="GremlinClient" /> class for the specified Gremlin Server.
         /// </summary>
-        public const string GraphSON2MimeType = "application/vnd.gremlin-v2.0+json";
+        /// <param name="gremlinServer">The <see cref="GremlinServer" /> the requests should be sent to.</param>
+        /// <param name="graphSONReader">A <see cref="GraphSONReader" /> instance to read received GraphSON data.</param>
+        /// <param name="graphSONWriter">a <see cref="GraphSONWriter" /> instance to write GraphSON data.</param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
+        /// <param name="webSocketConfiguration">
+        ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
+        ///     object used to configure WebSocket connections.
+        /// </param>
+        /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
+        [Obsolete("This constructor is obsolete. Use the constructor that takes a IMessageSerializer instead.")]
+        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader, GraphSONWriter graphSONWriter,
+            ConnectionPoolSettings connectionPoolSettings = null,
+            Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
+            : this(gremlinServer, graphSONReader, graphSONWriter, SerializationTokens.GraphSON3MimeType,
+                connectionPoolSettings, webSocketConfiguration, sessionId)
+        {
+        }
         
-        private readonly ConnectionPool _connectionPool;
-
         /// <summary>
         ///     Initializes a new instance of the <see cref="GremlinClient" /> class for the specified Gremlin Server.
         /// </summary>
@@ -54,24 +65,96 @@ namespace Gremlin.Net.Driver
         /// <param name="graphSONReader">A <see cref="GraphSONReader" /> instance to read received GraphSON data.</param>
         /// <param name="graphSONWriter">a <see cref="GraphSONWriter" /> instance to write GraphSON data.</param>
         /// <param name="mimeType">The GraphSON version mime type, defaults to latest supported by the server.</param>
-        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings"/> for the connection pool.</param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
+        /// <param name="webSocketConfiguration">
+        ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
+        ///     object used to configure WebSocket connections.
+        /// </param>
+        /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
+        [Obsolete("This constructor is obsolete. Use the constructor that takes a IMessageSerializer instead.")]
+        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader, GraphSONWriter graphSONWriter,
+            string mimeType, ConnectionPoolSettings connectionPoolSettings = null,
+            Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
+        {
+            IMessageSerializer messageSerializer;
+            switch (mimeType)
+            {
+                case SerializationTokens.GraphSON3MimeType:
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON3Reader>(graphSONReader, nameof(graphSONReader),
+                        mimeType);
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON3Writer>(graphSONWriter, nameof(graphSONWriter),
+                        mimeType);
+                    messageSerializer = new GraphSON3MessageSerializer(
+                        (GraphSON3Reader) graphSONReader ?? new GraphSON3Reader(),
+                        (GraphSON3Writer) graphSONWriter ?? new GraphSON3Writer());
+                    break;
+                case SerializationTokens.GraphSON2MimeType:
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON2Reader>(graphSONReader, nameof(graphSONReader),
+                        mimeType);
+                    VerifyGraphSONArgumentTypeForMimeType<GraphSON2Writer>(graphSONWriter, nameof(graphSONWriter),
+                        mimeType);
+                    messageSerializer = new GraphSON2MessageSerializer(
+                        (GraphSON2Reader) graphSONReader ?? new GraphSON2Reader(),
+                        (GraphSON2Writer) graphSONWriter ?? new GraphSON2Writer());
+                    break;
+                default:
+                    throw new ArgumentException(nameof(mimeType), $"{mimeType} not supported");
+            }
+            
+            var connectionFactory =
+                new ConnectionFactory(gremlinServer, messageSerializer, webSocketConfiguration, sessionId);
+
+            // make sure one connection in pool as session mode
+            if (!string.IsNullOrEmpty(sessionId))
+            {
+                if (connectionPoolSettings != null)
+                {
+                    if (connectionPoolSettings.PoolSize != 1)
+                        throw new ArgumentOutOfRangeException(nameof(connectionPoolSettings), "PoolSize must be 1 in session mode!");
+                }
+                else
+                {
+                    connectionPoolSettings = new ConnectionPoolSettings {PoolSize = 1};
+                }
+            }
+            _connectionPool =
+                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());
+        }
+
+        private static void VerifyGraphSONArgumentTypeForMimeType<T>(object argument, string argumentName,
+            string mimeType)
+        {
+            if (argument != null && !(argument is T))
+            {
+                throw new ArgumentException(
+                    $"{argumentName} is not a {typeof(T).Name} but the mime type is: {mimeType}", argumentName);
+            }
+        }
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GremlinClient" /> class for the specified Gremlin Server.
+        /// </summary>
+        /// <param name="gremlinServer">The <see cref="GremlinServer" /> the requests should be sent to.</param>
+        /// <param name="messageSerializer">
+        ///     A <see cref="IMessageSerializer" /> instance to serialize messages sent to and received
+        ///     from the server.
+        /// </param>
+        /// <param name="connectionPoolSettings">The <see cref="ConnectionPoolSettings" /> for the connection pool.</param>
         /// <param name="webSocketConfiguration">
         ///     A delegate that will be invoked with the <see cref="ClientWebSocketOptions" />
         ///     object used to configure WebSocket connections.
         /// </param>
         /// <param name="sessionId">The session Id if Gremlin Client in session mode, defaults to null as session-less Client.</param>
-        public GremlinClient(GremlinServer gremlinServer, GraphSONReader graphSONReader = null,
-            GraphSONWriter graphSONWriter = null, string mimeType = null,
+        public GremlinClient(GremlinServer gremlinServer, IMessageSerializer messageSerializer = null,
             ConnectionPoolSettings connectionPoolSettings = null,
             Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null)
         {
-            var reader = graphSONReader ?? new GraphSON3Reader();
-            var writer = graphSONWriter ?? new GraphSON3Writer();
-            var connectionFactory = new ConnectionFactory(gremlinServer, reader, writer, mimeType ?? DefaultMimeType,
-                webSocketConfiguration, sessionId);
+            messageSerializer = messageSerializer ?? new GraphSON3MessageSerializer();
+            var connectionFactory =
+                new ConnectionFactory(gremlinServer, messageSerializer, webSocketConfiguration, sessionId);
 
             // make sure one connection in pool as session mode
-            if (!String.IsNullOrEmpty(sessionId))
+            if (!string.IsNullOrEmpty(sessionId))
             {
                 if (connectionPoolSettings != null)
                 {
@@ -80,12 +163,11 @@ namespace Gremlin.Net.Driver
                 }
                 else
                 {
-                    connectionPoolSettings = new ConnectionPoolSettings();
-                    connectionPoolSettings.PoolSize = 1;
+                    connectionPoolSettings = new ConnectionPoolSettings {PoolSize = 1};
                 }
             }
             _connectionPool =
-                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());            
+                new ConnectionPool(connectionFactory, connectionPoolSettings ?? new ConnectionPoolSettings());
         }
 
         /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs
new file mode 100644
index 0000000..bdd9095
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/IMessageSerializer.cs
@@ -0,0 +1,48 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System.Collections.Generic;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Driver
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server.
+    /// </summary>
+    public interface IMessageSerializer
+    {
+        /// <summary>
+        ///     Serializes a <see cref="RequestMessage"/>.
+        /// </summary>
+        /// <param name="requestMessage">The <see cref="RequestMessage"/> to serialize.</param>
+        /// <returns>The serialized message.</returns>
+        byte[] SerializeMessage(RequestMessage requestMessage);
+        
+        /// <summary>
+        ///     Deserializes a <see cref="ResponseMessage{T}"/> from a byte array.
+        /// </summary>
+        /// <param name="message">The serialized message to deserialize.</param>
+        /// <returns>The deserialized <see cref="ResponseMessage{T}"/>.</returns>
+        ResponseMessage<List<object>> DeserializeMessage(byte[] message);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs
deleted file mode 100644
index de4c610..0000000
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/JsonMessageSerializer.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-#region License
-
-/*
- * 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.
- */
-
-#endregion
-
-using System;
-using System.Text;
-using System.Text.Json;
-
-namespace Gremlin.Net.Driver
-{
-    internal class JsonMessageSerializer
-    {
-        private readonly string _mimeType;
-        private static readonly JsonSerializerOptions JsonDeserializingOptions = new JsonSerializerOptions
-            {PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
-
-        public JsonMessageSerializer(string mimeType)
-        {
-            _mimeType = mimeType;
-        }
-
-        public byte[] SerializeMessage(string msg)
-        {
-            return Encoding.UTF8.GetBytes(MessageWithHeader(msg));
-        }
-
-        private string MessageWithHeader(string messageContent)
-        {
-            return $"{(char) _mimeType.Length}{_mimeType}{messageContent}";
-        }
-
-        public TMessage DeserializeMessage<TMessage>(byte[] message)
-        {
-            if (message == null) throw new ArgumentNullException(nameof(message));
-            if (message.Length == 0) return default;
-            var reader = new Utf8JsonReader(message);
-            var deserialized = JsonSerializer.Deserialize<TMessage>(ref reader, JsonDeserializingOptions);
-            return deserialized;
-        }
-    }
-}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
index 791433f..b8c0673 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseMessage.cs
@@ -25,12 +25,25 @@ using System;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseMessage
+    /// <summary>
+    ///     The message returned from the server.
+    /// </summary>
+    /// <typeparam name="T">The type of the data returned.</typeparam>
+    public class ResponseMessage<T>
     {
+        /// <summary>
+        ///     Gets or sets the identifier of the <see cref="RequestMessage"/> that generated this <see cref="ResponseMessage{T}"/>.
+        /// </summary>
         public Guid RequestId { get; set; }
 
+        /// <summary>
+        ///     Gets or sets status information about this <see cref="ResponseMessage{T}"/>.
+        /// </summary>
         public ResponseStatus Status { get; set; }
 
-        public ResponseResult Result { get; set; }
+        /// <summary>
+        ///     Gets or sets the result with its data and optional meta information.
+        /// </summary>
+        public ResponseResult<T> Result { get; set; }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
index b26f415..abc2907 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
@@ -22,14 +22,24 @@
 #endregion
 
 using System.Collections.Generic;
-using System.Text.Json;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseResult
+    /// <summary>
+    ///     Represents the result as a response to a <see cref="RequestMessage"/> sent as part of a
+    ///     <see cref="ResponseMessage{T}"/> by the server.
+    /// </summary>
+    /// <typeparam name="T">The type of the <see cref="Data"/>.</typeparam>
+    public class ResponseResult<T>
     {
-        public JsonElement Data { get; set; }
-        
+        /// <summary>
+        ///     Gets or sets the data of this result.
+        /// </summary>
+        public T Data { get; set; }
+
+        /// <summary>
+        ///     Gets or sets meta data of this result.
+        /// </summary>
         public Dictionary<string, object> Meta { get; set; }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
index 32d8b43..63530a3 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseStatus.cs
@@ -26,12 +26,24 @@ using Gremlin.Net.Driver.Exceptions;
 
 namespace Gremlin.Net.Driver.Messages
 {
-    internal class ResponseStatus
+    /// <summary>
+    ///     Represents status information of a <see cref="ResponseMessage{T}"/>.
+    /// </summary>
+    public class ResponseStatus
     {
+        /// <summary>
+        ///     Gets or sets the <see cref="ResponseStatusCode"/>.
+        /// </summary>
         public ResponseStatusCode Code { get; set; }
-        
+
+        /// <summary>
+        ///     Gets or sets the attributes <see cref="Dictionary{TKey,TValue}"/> with protocol-level information.
+        /// </summary>
         public Dictionary<string, object> Attributes { get; set; }
-        
+
+        /// <summary>
+        ///     Gets or sets the message which is just a human-readable string usually associated with errors.
+        /// </summary>
         public string Message { get; set; }
     }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs
similarity index 75%
rename from gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs
rename to gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs
index 13fbaf4..fafa7d9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/SingleMessageResultReceiver.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ResponseHandlerForSingleRequestMessage.cs
@@ -23,10 +23,8 @@
 
 using System;
 using System.Collections.Generic;
-using System.Text.Json;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
-using Gremlin.Net.Structure.IO.GraphSON;
 
 namespace Gremlin.Net.Driver
 {
@@ -36,23 +34,14 @@ namespace Gremlin.Net.Driver
 
         private readonly TaskCompletionSource<ResultSet<T>> _tcs =
             new TaskCompletionSource<ResultSet<T>>(TaskCreationOptions.RunContinuationsAsynchronously);
-
-        private readonly GraphSONReader _graphSONReader;
+        
         private readonly List<T> _result = new List<T>();
 
-        public ResponseHandlerForSingleRequestMessage(GraphSONReader graphSonReader)
-        {
-            _graphSONReader = graphSonReader;
-        }
-
-        public void HandleReceived(ResponseMessage received)
+        public void HandleReceived(ResponseMessage<List<object>> received)
         {
-            var receivedData = typeof(T) == typeof(JsonElement)
-                ? new[] {received.Result.Data}
-                : _graphSONReader.ToObject(received.Result.Data);
-            foreach (var d in receivedData)
+            foreach (var d in received.Result.Data)
             {
-                _result.Add(d);
+                _result.Add((T) d);
             }
         }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs
new file mode 100644
index 0000000..c0c36b1
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON2MessageSerializer.cs
@@ -0,0 +1,43 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON2 format.
+    /// </summary>
+    public class GraphSON2MessageSerializer : GraphSONMessageSerializer
+    {
+        private const string MimeType = SerializationTokens.GraphSON2MimeType;
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSON2MessageSerializer" /> class with custom serializers.
+        /// </summary>
+        /// <param name="graphSONReader">The <see cref="GraphSON2Reader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSONWriter">The <see cref="GraphSON2Writer"/> used to serialize to GraphSON.</param>
+        public GraphSON2MessageSerializer(GraphSON2Reader graphSONReader = null, GraphSON2Writer graphSONWriter = null)
+            : base(MimeType, graphSONReader ?? new GraphSON2Reader(), graphSONWriter ?? new GraphSON2Writer())
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs
new file mode 100644
index 0000000..abb6a75
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSON3MessageSerializer.cs
@@ -0,0 +1,43 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON3 format.
+    /// </summary>
+    public class GraphSON3MessageSerializer : GraphSONMessageSerializer
+    {
+        private const string MimeType = SerializationTokens.GraphSON3MimeType;
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSON3MessageSerializer" /> class with custom serializers.
+        /// </summary>
+        /// <param name="graphSONReader">The <see cref="GraphSON3Reader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSONWriter">The <see cref="GraphSON3Writer"/> used to serialize to GraphSON.</param>
+        public GraphSON3MessageSerializer(GraphSON3Reader graphSONReader = null, GraphSON3Writer graphSONWriter = null)
+            : base(MimeType, graphSONReader ?? new GraphSON3Reader(), graphSONWriter ?? new GraphSON3Writer())
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs
new file mode 100644
index 0000000..8c73319
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONMessageSerializer.cs
@@ -0,0 +1,100 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Messages;
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    /// <summary>
+    ///     Serializes data to and from Gremlin Server in GraphSON format.
+    /// </summary>
+    public abstract class GraphSONMessageSerializer : IMessageSerializer
+    {
+        private static readonly JsonSerializerOptions JsonDeserializingOptions = new JsonSerializerOptions
+            {PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
+        private readonly string _mimeType;
+        private readonly GraphSONReader _graphSONReader;
+        private readonly GraphSONWriter _graphSONWriter;
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="GraphSONMessageSerializer" /> class.
+        /// </summary>
+        /// <param name="mimeType">The MIME type supported by this serializer.</param>
+        /// <param name="graphSONReader">The <see cref="GraphSONReader"/> used to deserialize from GraphSON.</param>
+        /// <param name="graphSonWriter">The <see cref="GraphSONWriter"/> used to serialize to GraphSON.</param>
+        protected GraphSONMessageSerializer(string mimeType, GraphSONReader graphSONReader,
+            GraphSONWriter graphSonWriter)
+        {
+            _mimeType = mimeType;
+            _graphSONReader = graphSONReader;
+            _graphSONWriter = graphSonWriter;
+        }
+
+        /// <inheritdoc />
+        public byte[] SerializeMessage(RequestMessage requestMessage)
+        {
+            var graphSONMessage = _graphSONWriter.WriteObject(requestMessage);
+            return Encoding.UTF8.GetBytes(MessageWithHeader(graphSONMessage));
+        }
+
+        private string MessageWithHeader(string messageContent)
+        {
+            return $"{(char) _mimeType.Length}{_mimeType}{messageContent}";
+        }
+
+        /// <inheritdoc />
+        public ResponseMessage<List<object>> DeserializeMessage(byte[] message)
+        {
+            if (message == null) throw new ArgumentNullException(nameof(message));
+            if (message.Length == 0) return default;
+            
+            var reader = new Utf8JsonReader(message);
+            var responseMessage =
+                JsonSerializer.Deserialize<ResponseMessage<JsonElement>>(ref reader, JsonDeserializingOptions);
+            if (responseMessage == null) return null;
+            
+            var data = _graphSONReader.ToObject(responseMessage.Result.Data);
+            return CopyMessageWithNewData(responseMessage, data);
+        }
+
+        private static ResponseMessage<List<object>> CopyMessageWithNewData(ResponseMessage<JsonElement> origMsg,
+            dynamic data)
+        {
+            return new ResponseMessage<List<object>>
+            {
+                RequestId = origMsg.RequestId,
+                Status = origMsg.Status,
+                Result = new ResponseResult<List<object>>
+                {
+                    Data = data == null ? null : new List<object>(data),
+                    Meta = origMsg.Result.Meta
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
similarity index 62%
copy from gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
copy to gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
index b26f415..95cb124 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Messages/ResponseResult.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
@@ -21,15 +21,21 @@
 
 #endregion
 
-using System.Collections.Generic;
-using System.Text.Json;
-
-namespace Gremlin.Net.Driver.Messages
+namespace Gremlin.Net.Structure.IO
 {
-    internal class ResponseResult
+    /// <summary>
+    ///     String constants used for serialization.
+    /// </summary>
+    public class SerializationTokens
     {
-        public JsonElement Data { get; set; }
+        /// <summary>
+        ///     The MIME type for GraphSON 2.
+        /// </summary>
+        public const string GraphSON2MimeType = "application/vnd.gremlin-v2.0+json";
         
-        public Dictionary<string, object> Meta { get; set; }
+        /// <summary>
+        ///     The MIME type for GraphSON 3.
+        /// </summary>
+        public const string GraphSON3MimeType = "application/vnd.gremlin-v3.0+json";
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
index 906a117..24971b3 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Dev/Provider/IndexTests.cs
@@ -84,7 +84,7 @@ var graphsonReader = new GraphSON3Reader(
 var graphsonWriter = new GraphSON3Writer(
     new Dictionary<Type, IGraphSONSerializer> {{typeof(MyType), new MyClassWriter()}});
 
-var gremlinClient = new GremlinClient(new GremlinServer("localhost", 8182), graphsonReader, graphsonWriter);
+var gremlinClient = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2MessageSerializer());
 // end::supportingGremlinNetIO[]
         }
     }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
index 61264e0..234e6a7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Docs/Reference/GremlinVariantsTests.cs
@@ -65,8 +65,7 @@ var g = Traversal().WithRemote(remoteConnection);
         public void SerializationTest()
         {
 // tag::serialization[]
-var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2Reader(),
-    new GraphSON2Writer(), GremlinClient.GraphSON2MimeType);
+var client = new GremlinClient(new GremlinServer("localhost", 8182), new GraphSON2MessageSerializer());
 // end::serialization[]
         }
         
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
index 377040c..d0e2c1c 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientTests.cs
@@ -70,32 +70,6 @@ namespace Gremlin.Net.IntegrationTest.Driver
         }
 
         [Fact]
-        public async Task ShouldReturnResultWithoutDeserializingItForJsonElementType()
-        {
-            var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using var gremlinClient = new GremlinClient(gremlinServer);
-            const string gremlinScript = "'someString'";
-                
-            var response = await gremlinClient.SubmitWithSingleResultAsync<JsonElement>(gremlinScript);
-
-            //Expected:
-            /* {
-                  "@type": "g:List",
-                  "@value": [
-                    "someString"
-                  ]
-                }*/
-
-            Assert.IsType<JsonElement>(response);
-            Assert.Equal("g:List", response.GetProperty("@type").GetString());
-
-            var valueProperty = response.GetProperty("@value");
-            Assert.NotNull(valueProperty);
-            Assert.Equal(1, valueProperty.GetArrayLength());
-            Assert.Equal("someString", (valueProperty[0].GetString()));
-        }
-
-        [Fact]
         public async Task ShouldHandleResponseWithoutContent()
         {
             var gremlinServer = new GremlinServer(TestHost, TestPort);
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs
similarity index 67%
rename from gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs
rename to gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs
index 79c1731..af8d9bf 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/JsonMessageSerializerTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GraphSONMessageSerializerTests.cs
@@ -21,48 +21,52 @@
 
 #endregion
 
-using Gremlin.Net.Driver;
-using Gremlin.Net.Driver.Messages;
 using System;
 using System.Text;
+using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
 
 namespace Gremlin.Net.UnitTest.Driver
 {
-    public class JsonMessageSerializerTests
+    public class GraphSONMessageSerializerTests
     {
         [Fact]
         public void DeserializingNullThrows()
         {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
+            var sut = CreateMessageSerializer();
 
-            Assert.Throws<ArgumentNullException>(()=> sut.DeserializeMessage<ResponseMessage>(null));
+            Assert.Throws<ArgumentNullException>(()=> sut.DeserializeMessage(null));
         }
 
         [Fact]
         public void EmptyArrayDeserializedIntoNull()
         {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
+            var sut = CreateMessageSerializer();
 
-            Assert.Null(sut.DeserializeMessage<ResponseMessage>(new byte[0]));            
+            Assert.Null(sut.DeserializeMessage(new byte[0]));            
         }
 
         [Fact]
         public void EmptyStringDeserializedIntoNull()
         {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
+            var sut = CreateMessageSerializer();
             var ofEmpty = Encoding.UTF8.GetBytes("");
 
-            Assert.Null(sut.DeserializeMessage<ResponseMessage>(ofEmpty));
+            Assert.Null(sut.DeserializeMessage(ofEmpty));
         }
 
         [Fact]
         public void JsonNullDeserializedIntoNull()
         {
-            var sut = new JsonMessageSerializer(GremlinClient.DefaultMimeType);
+            var sut = CreateMessageSerializer();
             var ofNull = Encoding.UTF8.GetBytes("null");
 
-            Assert.Null(sut.DeserializeMessage<ResponseMessage>(ofNull));
+            Assert.Null(sut.DeserializeMessage(ofNull));
+        }
+
+        private static GraphSONMessageSerializer CreateMessageSerializer()
+        {
+            return new GraphSON3MessageSerializer(new GraphSON3Reader(), new GraphSON3Writer());
         }
     }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
index 086dc90..5f1e4c5 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/GremlinClientTests.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -23,6 +23,8 @@
 
 using System;
 using Gremlin.Net.Driver;
+using Gremlin.Net.Structure.IO;
+using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;
 
 namespace Gremlin.Net.UnitTest.Driver
@@ -39,7 +41,40 @@ namespace Gremlin.Net.UnitTest.Driver
             var poolSettings = new ConnectionPoolSettings {PoolSize = 2};
 
             var gremlinServer = new GremlinServer(host, port);
-            Assert.Throws<ArgumentOutOfRangeException>(() => new GremlinClient(gremlinServer, connectionPoolSettings: poolSettings, sessionId: sessionId));
+            Assert.Throws<ArgumentOutOfRangeException>(() =>
+                new GremlinClient(gremlinServer, connectionPoolSettings: poolSettings, sessionId: sessionId));
         }
+
+#pragma warning disable 612,618
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONReaderWriterCombination()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON2Reader(), new GraphSON3Writer()));
+        }
+        
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONReaderForGivenMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON3Reader(), new GraphSON2Writer(),
+                    SerializationTokens.GraphSON2MimeType));
+        }
+        
+        [Fact]
+        public void ShouldThrowForInvalidGraphSONWriterForGivenMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON2Reader(), new GraphSON3Writer(),
+                    SerializationTokens.GraphSON2MimeType));
+        }
+
+        [Fact]
+        public void ShouldThrowForUnsupportedMimeType()
+        {
+            Assert.Throws<ArgumentException>(() =>
+                new GremlinClient(new GremlinServer(), new GraphSON3Reader(), new GraphSON3Writer(), "unsupported"));
+        }
+#pragma warning restore 612,618
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
index 29a434f..ad78334 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/BytecodeGraphSONSerializerTests.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -22,7 +22,6 @@
 #endregion
 
 using System.Collections.Generic;
-using System.Numerics;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Structure.IO.GraphSON;
 using Xunit;