This is an automated email from the ASF dual-hosted git repository. xiazcy pushed a commit to branch TINKERPOP-3186_dotnet in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 4505a0a74f8824bd6299a424de762f20701562ca Author: xiazcy <[email protected]> AuthorDate: Wed Oct 29 21:14:06 2025 -0700 Normalized Element.properties in .NET to return empty arrays when null --- CHANGELOG.asciidoc | 1 + docs/src/upgrade/release-3.8.x.asciidoc | 13 +++++++------ gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs | 4 ++-- .../Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs | 2 +- .../Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs | 2 +- .../Structure/IO/GraphSON/VertexPropertyDeserializer.cs | 2 +- .../Traversal/DriverRemoteConnection/GraphTraversalTests.cs | 8 ++++---- .../Structure/IO/GraphSON/GraphSONReaderTests.cs | 5 +++++ 8 files changed, 22 insertions(+), 15 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..14a2acda44 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/EdgeDeserializer.cs @@ -45,7 +45,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON ? labelProperty.GetString()! : "edge"; - dynamic[]? properties = null; + dynamic[] properties = System.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..c9c72e09fd 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/VertexDeserializer.cs @@ -36,7 +36,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON ? labelProperty.GetString()! : Vertex.DefaultLabel; - dynamic[]? properties = null; + dynamic[] properties = System.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..6903c04be2 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 @@ -330,7 +330,7 @@ namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection { Assert.NotNull(vp); // GraphSON will deserialize into null and GraphBinary to [] - Assert.True(vp.Properties == null || vp.Properties.Length == 0); + Assert.True(vp.Properties.Length == 0); } } @@ -353,9 +353,9 @@ namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection 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.True(a.Properties.Length == 0); + Assert.True(b.Properties.Length == 0); + Assert.True(c.Properties.Length == 0); } [Fact] 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))]
