You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2021/11/09 11:31:47 UTC

[tinkerpop] 01/01: TINKERPOP-2613 Improved behavior of V(null)

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

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

commit 1d2a8453e09fb53f721b076dc11fbb87d18bf244
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Tue Nov 9 06:27:40 2021 -0500

    TINKERPOP-2613 Improved behavior of V(null)
    
    Prevented NPE and instead filtered results.
---
 CHANGELOG.asciidoc                                 |  1 +
 .../traversal/dsl/graph/GraphTraversal.java        |  9 ++--
 .../traversal/dsl/graph/GraphTraversalSource.java  | 14 ++++--
 .../gremlin/structure/util/ElementHelper.java      |  4 +-
 .../translator/JavascriptTranslatorTest.java       |  8 +++-
 .../Process/Traversal/GraphTraversal.cs            | 11 ++++-
 .../Process/Traversal/GraphTraversalSource.cs      | 22 +++++++--
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  5 ++
 gremlin-javascript/build/generate.groovy           |  4 ++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  5 ++
 gremlin-python/src/main/python/radish/gremlin.py   |  5 ++
 gremlin-test/features/map/Vertex.feature           | 54 ++++++++++++++++++++++
 .../gremlin/tinkergraph/structure/TinkerGraph.java |  2 +
 13 files changed, 126 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d3fc76a..e3c1e7f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ limitations under the License.
 * Created `gremlin-annotations` module where the `@GremlinDsl` annotation and related code has been moved.
 * Removed `groovy` and `groovy-json` dependencies from `gremlin-driver` as well as related `JsonBuilder` serialization support.
 * Replaced log4j usage with logback where builds rely on and packaged distributions now contain the latter.
+* Improved behavior of `V()` when `null` is an argument producing a filtering behavior rather than an exception.
 * Prevented metrics computation unless the traversal is in a locked state.
 * Created a way to produce a corpus of Gremlin traversals via `FeatureReader` and `DocumentationReader` in `gremlin-language`.
 * Exposed Gherkin tests as part of the provider test suite.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 9a45300..cd64f55 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -315,8 +315,10 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @since 3.1.0-incubating
      */
     public default GraphTraversal<S, Vertex> V(final Object... vertexIdsOrElements) {
-        this.asAdmin().getBytecode().addStep(Symbols.V, vertexIdsOrElements);
-        return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, vertexIdsOrElements));
+        // a single null is [null]
+        final Object[] ids = null == vertexIdsOrElements ? new Object[] { null } : vertexIdsOrElements;
+        this.asAdmin().getBytecode().addStep(Symbols.V, ids);
+        return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, ids));
     }
 
     /**
@@ -1606,8 +1608,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     public default GraphTraversal<S, E> hasId(final Object id, final Object... otherIds) {
         if (id instanceof P) {
             return this.hasId((P) id);
-        }
-        else {
+        } else {
             Object[] ids;
             if (id instanceof Object[]) {
                 ids = (Object[]) id;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index b7471b1..cae7e5c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -365,21 +365,25 @@ public class GraphTraversalSource implements TraversalSource {
      * unique identifier.
      */
     public GraphTraversal<Vertex, Vertex> V(final Object... vertexIds) {
+        // a single null is [null]
+        final Object[] ids = null == vertexIds ? new Object[] { null } : vertexIds;
         final GraphTraversalSource clone = this.clone();
-        clone.bytecode.addStep(GraphTraversal.Symbols.V, vertexIds);
+        clone.bytecode.addStep(GraphTraversal.Symbols.V, ids);
         final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
-        return traversal.addStep(new GraphStep<>(traversal, Vertex.class, true, vertexIds));
+        return traversal.addStep(new GraphStep<>(traversal, Vertex.class, true, ids));
     }
 
     /**
      * Spawns a {@link GraphTraversal} starting with all edges or some subset of edges as specified by their unique
      * identifier.
      */
-    public GraphTraversal<Edge, Edge> E(final Object... edgesIds) {
+    public GraphTraversal<Edge, Edge> E(final Object... edgeIds) {
+        // a single null is [null]
+        final Object[] ids = null == edgeIds ? new Object[] { null } : edgeIds;
         final GraphTraversalSource clone = this.clone();
-        clone.bytecode.addStep(GraphTraversal.Symbols.E, edgesIds);
+        clone.bytecode.addStep(GraphTraversal.Symbols.E, ids);
         final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(clone);
-        return traversal.addStep(new GraphStep<>(traversal, Edge.class, true, edgesIds));
+        return traversal.addStep(new GraphStep<>(traversal, Edge.class, true, ids));
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
index 48e8733..a742e7b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
@@ -549,10 +549,10 @@ public final class ElementHelper {
         // it is OK to evaluate equality of ids via toString() now given that the toString() the test suite
         // enforces the value of id.()toString() to be a first class representation of the identifier
         if (1 == providedIds.length) {
-            return id.toString().equals(providedIds[0].toString());
+            return id != null && providedIds[0] != null && id.toString().equals(providedIds[0].toString());
         } else {
             for (final Object temp : providedIds) {
-                if (temp.toString().equals(id.toString()))
+                if (id != null && temp != null && temp.toString().equals(id.toString()))
                     return true;
             }
             return false;
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
index 1a0f1c0..f2db89b 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
@@ -119,7 +119,13 @@ public class JavascriptTranslatorTest {
 
     @Test
     public void shouldHaveNull() {
-        translator.translate(g.inject(null, null).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(null,null)", translator.translate(g.inject(null, null).asAdmin().getBytecode()).getScript());
+        assertEquals("g.V()", translator.translate(g.V().asAdmin().getBytecode()).getScript());
+        assertEquals("g.V(null)", translator.translate(g.V(null).asAdmin().getBytecode()).getScript());
+        assertEquals("g.V(null,null)", translator.translate(g.V(null, null).asAdmin().getBytecode()).getScript());
+        assertEquals("g.E()", translator.translate(g.E().asAdmin().getBytecode()).getScript());
+        assertEquals("g.E(null)", translator.translate(g.E(null).asAdmin().getBytecode()).getScript());
+        assertEquals("g.E(null,null)", translator.translate(g.E(null, null).asAdmin().getBytecode()).getScript());
     }
 
     @Test
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 2bc4de8..328e506 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -79,8 +79,15 @@ namespace Gremlin.Net.Process.Traversal
         /// </summary>
         public GraphTraversal<S, Vertex> V (params object[] vertexIdsOrElements)
         {
-            var args = new List<object>(0 + vertexIdsOrElements.Length) {};
-            args.AddRange(vertexIdsOrElements);
+            var args = null == vertexIdsOrElements ? new List<object>(1) {} : new List<object>(0 + vertexIdsOrElements.Length) {};
+            if (null == vertexIdsOrElements)
+            {
+                args.Add(null);
+            }
+            else
+            {
+                args.AddRange(vertexIdsOrElements);
+            }
             Bytecode.AddStep("V", args.ToArray());
             return Wrap<S, Vertex>(this);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
index 2ab9d01..ae5b1d9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
@@ -296,8 +296,15 @@ namespace Gremlin.Net.Process.Traversal
         public GraphTraversal<Edge, Edge> E(params object[] edgesIds)
         {
             var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode));
-            var args = new List<object>(0 + edgesIds.Length) {};
-            args.AddRange(edgesIds);
+            var args = null == edgesIds ? new List<object>(1) {} : new List<object>(0 + edgesIds.Length) {};
+            if (null == edgesIds)
+            {
+                args.Add(null);
+            }
+            else
+            {
+                args.AddRange(edgesIds);
+            }
             traversal.Bytecode.AddStep("E", args.ToArray());
             return traversal;
         }
@@ -309,8 +316,15 @@ namespace Gremlin.Net.Process.Traversal
         public GraphTraversal<Vertex, Vertex> V(params object[] vertexIds)
         {
             var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode));
-            var args = new List<object>(0 + vertexIds.Length) {};
-            args.AddRange(vertexIds);
+            var args = null == vertexIds ? new List<object>(1) {} : new List<object>(0 + vertexIds.Length) {};
+            if (null == vertexIds)
+            {
+                args.Add(null);
+            }
+            else
+            {
+                args.AddRange(vertexIds);
+            }
             traversal.Bytecode.AddStep("V", args.ToArray());
             return traversal;
         }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 2c8d242..8cd8876 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -646,6 +646,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object,object>().With("~tinkerpop.valueMap.tokens")}}, 
                {"g_VX1X_valueMapXname_locationX_byXunfoldX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ValueMap<object,object>("name","location").By(__.Unfold<object>()).By()}}, 
                {"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age",null)}}, 
+               {"g_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(null)}}, 
+               {"g_VXlistXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"])}}, 
+               {"g_VX1_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],null)}}, 
                {"g_VXlistX1_2_3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}}, 
                {"g_VXlistXv1_v2_v3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}}, 
                {"g_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V()}}, 
@@ -686,6 +689,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").V().HasLabel("software").Values<object>("name")}}, 
                {"g_V_hasLabelXloopsX_bothEXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").BothE("self")}}, 
                {"g_V_hasLabelXloopsX_bothXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").Both("self")}}, 
+               {"g_injectX1X_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(1).V(null)}}, 
+               {"g_injectX1X_VX1_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(1).V(p["vid1"],null)}}, 
                {"Primitives_Number_eqXintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, 
                {"g_V_valueXnameX_aggregateXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}}, 
                {"g_V_valueXnameX_aggregateXglobal_xX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate(Scope.Global,"x").Cap<object>("x")}}, 
diff --git a/gremlin-javascript/build/generate.groovy b/gremlin-javascript/build/generate.groovy
index 75e7087..572d29c 100644
--- a/gremlin-javascript/build/generate.groovy
+++ b/gremlin-javascript/build/generate.groovy
@@ -99,6 +99,10 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
     // solution may become necessary as testing of nulls expands.
     def staticTranslate = [
             g_injectXnull_nullX: "    g_injectXnull_nullX: [function({g}) { return g.inject(null,null) }], ",
+            g_V_hasIdXnullX: "    g_V_hasIdXnullX: [function({g}) { return g.V().hasId(null) }], ",
+            g_V_hasIdX1_nullX: "    g_V_hasIdX1_nullX: [function({g, vid1}) { return g.V().hasId(vid1,null) }], ",
+            g_injectX1X_VXnullX: "    g_injectX1X_VXnullX: [function({g}) { return g.inject(1).V(null) }], ",
+            g_injectX1X_VX1_nullX: "    g_injectX1X_VX1_nullX: [function({g, vid1}) { return g.inject(1).V(vid1,null) }], ",
             g_VX1X_valuesXageX_injectXnull_nullX: "    g_VX1X_valuesXageX_injectXnull_nullX: [function({g, xx1}) { return g.V(xx1).values(\"age\").inject(null,null) }], "
     ]
 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 8507405..a993219 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -635,6 +635,9 @@ const gremlins = {
     g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap().with_("~tinkerpop.valueMap.tokens") }], 
     g_VX1X_valueMapXname_locationX_byXunfoldX_by: [function({g, vid1}) { return g.V(vid1).valueMap("name","location").by(__.unfold()).by() }], 
     g_V_valueMapXname_age_nullX: [function({g}) { return g.V().valueMap("name","age",null) }], 
+    g_VXnullX: [function({g}) { return g.V(null) }], 
+    g_VXlistXnullXX: [function({g, xx1}) { return g.V(xx1) }], 
+    g_VX1_nullX: [function({g, vid1}) { return g.V(vid1,null) }], 
     g_VXlistX1_2_3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
     g_VXlistXv1_v2_v3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
     g_V: [function({g}) { return g.V() }], 
@@ -675,6 +678,8 @@ const gremlins = {
     g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name: [function({g}) { return g.V().hasLabel("person").V().hasLabel("software").values("name") }], 
     g_V_hasLabelXloopsX_bothEXselfX: [function({g}) { return g.V().hasLabel("loops").bothE("self") }], 
     g_V_hasLabelXloopsX_bothXselfX: [function({g}) { return g.V().hasLabel("loops").both("self") }], 
+    g_injectX1X_VXnullX: [function({g}) { return g.inject(1).V(null) }], 
+    g_injectX1X_VX1_nullX: [function({g, vid1}) { return g.inject(1).V(vid1,null) }], 
     Primitives_Number_eqXintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
     g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }], 
     g_V_valueXnameX_aggregateXglobal_xX_capXxX: [function({g}) { return g.V().values("name").aggregate(Scope.global,"x").cap("x") }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 5f9535a..e4b187f 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -620,6 +620,9 @@ world.gremlins = {
     'g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX': [(lambda g:g.V().hasLabel('person').filter(__.outE('created')).valueMap().with_('~tinkerpop.valueMap.tokens'))], 
     'g_VX1X_valueMapXname_locationX_byXunfoldX_by': [(lambda g, vid1=None:g.V(vid1).valueMap('name','location').by(__.unfold()).by())], 
     'g_V_valueMapXname_age_nullX': [(lambda g:g.V().valueMap('name','age',None))], 
+    'g_VXnullX': [(lambda g:g.V(None))], 
+    'g_VXlistXnullXX': [(lambda g, xx1=None:g.V(xx1))], 
+    'g_VX1_nullX': [(lambda g, vid1=None:g.V(vid1,None))], 
     'g_VXlistX1_2_3XX_name': [(lambda g, xx1=None:g.V(xx1).name)], 
     'g_VXlistXv1_v2_v3XX_name': [(lambda g, xx1=None:g.V(xx1).name)], 
     'g_V': [(lambda g:g.V())], 
@@ -660,6 +663,8 @@ world.gremlins = {
     'g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name': [(lambda g:g.V().hasLabel('person').V().hasLabel('software').name)], 
     'g_V_hasLabelXloopsX_bothEXselfX': [(lambda g:g.V().hasLabel('loops').bothE('self'))], 
     'g_V_hasLabelXloopsX_bothXselfX': [(lambda g:g.V().hasLabel('loops').both('self'))], 
+    'g_injectX1X_VXnullX': [(lambda g:g.inject(1).V(None))], 
+    'g_injectX1X_VX1_nullX': [(lambda g, vid1=None:g.inject(1).V(vid1,None))], 
     'Primitives_Number_eqXintX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], 
     'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda g:g.V().name.aggregate('x').cap('x'))], 
     'g_V_valueXnameX_aggregateXglobal_xX_capXxX': [(lambda g:g.V().name.aggregate(Scope.global_,'x').cap('x'))], 
diff --git a/gremlin-test/features/map/Vertex.feature b/gremlin-test/features/map/Vertex.feature
index 37738bb..3e78c82 100644
--- a/gremlin-test/features/map/Vertex.feature
+++ b/gremlin-test/features/map/Vertex.feature
@@ -18,6 +18,37 @@
 @StepClassMap @StepVertex
 Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
 
+  Scenario: g_VXnullX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V(null)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  Scenario: g_VXlistXnullXX
+    Given the modern graph
+    And using the parameter xx1 defined as "l[null]"
+    And the traversal of
+      """
+      g.V(xx1)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  Scenario: g_VX1_nullX
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1,null)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+
   Scenario: g_VXlistX1_2_3XX_name
     Given the modern graph
     And using the parameter xx1 defined as "l[v[marko].id,v[vadas].id,v[lop].id]"
@@ -579,3 +610,26 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | result |
       | v[loop] |
       | v[loop] |
+
+  @GraphComputerVerificationInjectionNotSupported @GraphComputerVerificationMidVNotSupported
+  Scenario: g_injectX1X_VXnullX
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject(1).V(null)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  @GraphComputerVerificationInjectionNotSupported @GraphComputerVerificationMidVNotSupported
+  Scenario: g_injectX1X_VX1_nullX
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.inject(1).V(vid1,null)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
\ No newline at end of file
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index 0343302..b9dda16 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -316,6 +316,8 @@ public final class TinkerGraph implements Graph {
             // the assumption is that if it's already an Element, its identifier must be valid to the Graph and to
             // its associated IdManager. All other objects are passed to the IdManager for conversion.
             return new TinkerGraphIterator<>(IteratorUtils.filter(IteratorUtils.map(idList, id -> {
+                // ids cant be null so all of those filter out
+                if (null == id) return null;
                 final Object iid = clazz.isAssignableFrom(id.getClass()) ? clazz.cast(id).id() : idManager.convert(id);
                 return elements.get(idManager.convert(iid));
             }).iterator(), Objects::nonNull));