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

xiazcy pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.8-dev by this push:
     new 074d634ac0 [TINKERPOP-3186] - Align Element.properties type for dotnet 
(#3257)
074d634ac0 is described below

commit 074d634ac01a01bfe5b3558b573ba4695030c1bf
Author: Yang Xia <[email protected]>
AuthorDate: Thu Oct 30 15:20:33 2025 -0700

    [TINKERPOP-3186] - Align Element.properties type for dotnet (#3257)
    
    Normalized Element.properties in .NET to return empty arrays when null
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/upgrade/release-3.8.x.asciidoc            | 13 ++++++-----
 .../src/Gremlin.Net/Structure/Element.cs           |  4 ++--
 .../Structure/IO/GraphSON/EdgeDeserializer.cs      |  3 ++-
 .../Structure/IO/GraphSON/VertexDeserializer.cs    |  3 ++-
 .../IO/GraphSON/VertexPropertyDeserializer.cs      |  2 +-
 .../DriverRemoteConnection/GraphTraversalTests.cs  | 26 +++++++++-------------
 .../Structure/IO/GraphSON/GraphSONReaderTests.cs   |  5 +++++
 8 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index c01b80c945..171b7f760f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -33,6 +33,7 @@ This release also includes changes from <<release-3-7-XXX, 
3.7.XXX>>.
 * Removed Vertex/ReferenceVertex from grammar. Use vertex id in traversals now 
instead.
 * Removed `has(key, traversal)` and `has(T, traversal)` options for `has()` 
step.
 * Fixed bug where `InlineFilterStrategy` could add an empty `has()`.
+* Normalized dotnet `Element.properties` to lists.
 * Normalized python and javascript `Element.properties` to lists.
 * Renamed `none()` step to `discard()`.
 * Repurposed `none()` step as a list filtering step with the signature 
`none(P)`.
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc 
b/docs/src/upgrade/release-3.8.x.asciidoc
index 9f254b581d..75ce68d0a1 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -625,18 +625,19 @@ See: 
link:https://issues.apache.org/jira/browse/TINKERPOP-1463[TINKERPOP-1463]
 
 ==== Serialization Changes
 
-*Properties on Element Serialization in Python & Javascript*
+*Properties on Element Serialization in GLVs*
 
 Element properties handling has been inconsistent across GLVs. 
Previously,`gremlin-python` deserialized empty properties
-as None or array depending on the serializer, while `gremlin-javascript` 
returned properties as objects or arrays, with
-empty properties as empty lists or undefined depending on the serializer.
+as `None` or array depending on the serializer, while `gremlin-javascript`, 
and `gremlin-dotnet` returned properties as
+objects or arrays, with empty properties as empty lists or undefined depending 
on the serializer. (Note that
+`gremlin-go` already returns empty slices for null properties so no changes is 
needed.)
 
 This inconsistency is now resolved, aligning to how properties are handled in 
Gremlin core and in the Java GLV.
-Both GLVs will deserialize element properties into lists of property objects, 
returning empty lists instead of null values
+All GLVs will deserialize element properties into lists of property objects, 
returning empty lists instead of null values
 for missing properties.
 
-For python, the most notable difference is in graphSON when "tokens" is turned 
on for "materializeProperties". The
-properties returned are no longer `None`, but empty lists. Users should update 
their code accordingly.
+For python and dotnet, the most notable difference is in graphSON when 
"tokens" is turned on for "materializeProperties". The
+properties returned are no longer `None` or `null`, but empty lists. Users 
should update their code accordingly.
 
 For javascript, the change is slightly more extensive, as user should no 
longer expect javascript objects to be returned.
 All properties are returned as lists of Property or VertexProperty objects.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs 
b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
index 32935bd6d6..bb2cdf4164 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
@@ -41,7 +41,7 @@ namespace Gremlin.Net.Structure
         {
             Id = id;
             Label = label;
-            Properties = properties;
+            Properties = properties ?? Array.Empty<dynamic>();
         }
 
         /// <summary>
@@ -57,7 +57,7 @@ namespace Gremlin.Net.Structure
         /// <summary>
         ///     Gets the properties of this <see cref="Element" />.
         /// </summary>
-        public dynamic[]? Properties { get; }
+        public dynamic[] Properties { get; }
 
         /// <inheritdoc />
         public bool Equals(Element? other)
diff --git 
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs 
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
index 4ab5ecdc2d..91e5feaf33 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs
@@ -21,6 +21,7 @@
 
 #endregion
 
+using System;
 using System.Linq;
 using System.Text.Json;
 
@@ -45,7 +46,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
                 ? labelProperty.GetString()!
                 : "edge";
 
-            dynamic[]? properties = null;
+            dynamic[] properties = Array.Empty<dynamic>();
             if (graphsonObject.TryGetProperty("properties", out var 
propertiesObject)
                 && propertiesObject.ValueKind == JsonValueKind.Object)
             {
diff --git 
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs 
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
index 2412c9a27b..d0321af667 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs
@@ -21,6 +21,7 @@
 
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text.Json;
@@ -36,7 +37,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
                 ? labelProperty.GetString()!
                 : Vertex.DefaultLabel;
 
-            dynamic[]? properties = null;
+            dynamic[] properties = Array.Empty<dynamic>();
             if (graphsonObject.TryGetProperty("properties", out var 
propertiesObject)
                 && propertiesObject.ValueKind == JsonValueKind.Object)
             {
diff --git 
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
 
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
index e8e919bee4..0714bc09de 100644
--- 
a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
+++ 
b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexPropertyDeserializer.cs
@@ -37,7 +37,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
                 ? new Vertex(reader.ToObject(vertexProperty))
                 : null;
 
-            Property[]? properties = null;
+            Property[] properties = System.Array.Empty<Property>();
             if (graphsonObject.TryGetProperty("properties", out var 
propertiesObject)
                 && propertiesObject.ValueKind == JsonValueKind.Object)
             {
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 4f1799450e..c939ac900f 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -293,7 +293,7 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
         }
         
         [Fact]
-        public void shouldUseMaterializedPropertiesTokenInV()
+        public void ShouldUseMaterializedPropertiesTokenInV()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
             var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -301,13 +301,12 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             foreach (var v in vertices)
             {
                 Assert.NotNull(v);
-                // GraphSON will deserialize into null and GraphBinary to []
-                Assert.True(v.Properties == null || v.Properties.Length == 0);
+                Assert.Empty(v.Properties);
             }
         }
         
         [Fact]
-        public void shouldUseMaterializedPropertiesTokenInE()
+        public void ShouldUseMaterializedPropertiesTokenInE()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
             var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -315,13 +314,12 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             foreach (var e in edges)
             {
                 Assert.NotNull(e);
-                // GraphSON will deserialize into null and GraphBinary to []
-                Assert.True(e.Properties == null || e.Properties.Length == 0);
+                Assert.Empty(e.Properties);
             }
         }
         
         [Fact]
-        public void shouldUseMaterializedPropertiesTokenInVP()
+        public void ShouldUseMaterializedPropertiesTokenInVP()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
             var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -329,13 +327,12 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             foreach (var vp in vps)
             {
                 Assert.NotNull(vp);
-                // GraphSON will deserialize into null and GraphBinary to []
-                Assert.True(vp.Properties == null || vp.Properties.Length == 
0);
+                Assert.Empty(vp.Properties);
             }
         }
         
         [Fact]
-        public void shouldUseMaterializedPropertiesTokenInPath()
+        public void ShouldUseMaterializedPropertiesTokenInPath()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
             var g = AnonymousTraversalSource.Traversal().With(connection);
@@ -352,14 +349,13 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             Assert.NotNull(b);
             Assert.NotNull(c);
             
-            // GraphSON will deserialize into null and GraphBinary to []
-            Assert.True(a.Properties == null || a.Properties.Length == 0);
-            Assert.True(b.Properties == null || b.Properties.Length == 0);
-            Assert.True(c.Properties == null || c.Properties.Length == 0);
+            Assert.Empty(a.Properties);
+            Assert.Empty(b.Properties);
+            Assert.Empty(c.Properties);
         }
         
         [Fact]
-        public void shouldMaterializePropertiesAllInPath()
+        public void ShouldMaterializePropertiesAllInPath()
         {
             var connection = _connectionFactory.CreateRemoteConnection();
             var g = AnonymousTraversalSource.Traversal().With(connection);
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
 
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
index e903c19b82..a7d314d5be 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
@@ -395,6 +395,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             Assert.Equal(new Vertex(5L), readPath[0]);
             Assert.Equal(new Vertex(5L), readPath["z"]);
             Assert.Single(readPath);
+            Assert.Empty(readPath[0]!.Properties);
         }
         
         [Theory, MemberData(nameof(Versions))]
@@ -459,6 +460,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             Assert.Equal("aKey", readVertexProperty.Label);
             Assert.True(readVertexProperty.Value);
             Assert.NotNull(readVertexProperty.Vertex);
+            Assert.Empty(readVertexProperty.Properties);
         }
         
         [Theory, MemberData(nameof(Versions))]
@@ -475,6 +477,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             Assert.Equal("name", readVertexProperty.Label);
             Assert.Equal("marko", readVertexProperty.Value);
             Assert.Null(readVertexProperty.Vertex);
+            Assert.Empty(readVertexProperty.Properties);
         }
         
         [Theory, MemberData(nameof(Versions))]
@@ -488,6 +491,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             var deserializedValue = reader.ToObject(jsonElement);
         
             Assert.Equal(new Vertex(45.23f), deserializedValue);
+            Assert.Empty(deserializedValue!.Properties);
         }
         
         [Theory, MemberData(nameof(Versions))]
@@ -501,6 +505,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             Vertex deserializedValue = reader.ToObject(jsonElement)!;
         
             Assert.Equal("person", deserializedValue.Label);
+            Assert.Empty(deserializedValue.Properties);
         }
         
         [Theory, MemberData(nameof(Versions))]

Reply via email to