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

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

commit 67b8a334ebb312ebfafa404c39285d52e275ad2d
Author: Stephen Mallette <[email protected]>
AuthorDate: Wed Dec 13 11:44:05 2023 -0500

    TINKERPOP-3022 Fixed JavaTranslator issues with has(String,null)
    
    Needed to better handle defaults for has(String,Traversal) on the case 
where reflection in JavaTranslator chose that method for has(String,null). CTR
---
 CHANGELOG.asciidoc                                           |  1 +
 .../gremlin/process/traversal/dsl/graph/GraphTraversal.java  | 12 ++++++++++++
 .../test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs      |  1 +
 gremlin-go/driver/cucumber/gremlin.go                        |  1 +
 .../javascript/gremlin-javascript/test/cucumber/gremlin.js   |  1 +
 gremlin-python/src/main/python/radish/gremlin.py             |  1 +
 .../tinkerpop/gremlin/test/features/filter/Has.feature       | 11 ++++++++++-
 7 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 60307513e1..fa3f2608fa 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Improved error message from `JavaTranslator` by including exception source.
 * Added tests for error handling for GLV's if tx.commit() is called remotely 
for graphs without transactions support.
 * Introduced multi-architecture AMD64/ARM64 docker images for gremlin-console.
+* Fixed bug in `JavaTranslator` where `has(String, null)` could call 
`has(String, Traversal)` to generate an error.
 
 [[release-3-6-6]]
 === TinkerPop 3.6.6 (November 20, 2023)
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 d92d2e09e7..7fbfbd8a00 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
@@ -1564,6 +1564,11 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> has(final String propertyKey, final 
P<?> predicate) {
+        // Groovy can get the overload wrong for has(T, null) which should 
probably go at has(T,Object). users could
+        // explicit cast but a redirect here makes this a bit more seamless
+        if (null == predicate)
+            return has(propertyKey, (Object) null);
+
         this.asAdmin().getBytecode().addStep(Symbols.has, propertyKey, 
predicate);
         return TraversalHelper.addHasContainer(this.asAdmin(), new 
HasContainer(propertyKey, predicate));
     }
@@ -1710,6 +1715,13 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> has(final String propertyKey, final 
Traversal<?, ?> propertyTraversal) {
+        // the translation here of null to has(String, Object) is likely what 
was intended. a null Traversal doesn't
+        // really make much sense. this should resolve issues with 
JavaTranslator grabbing this method when bytecode
+        // uses null as the second argument. we've taken this tactic for other 
overloads of has() as well, so just
+        // continuing with that pattern.
+        if (null == propertyTraversal)
+            return has(propertyKey, (Object) null);
+
         this.asAdmin().getBytecode().addStep(Symbols.has, propertyKey, 
propertyTraversal);
         return this.asAdmin().addStep(
                 new TraversalFilterStep<>(this.asAdmin(), 
propertyTraversal.asAdmin().addStep(0,
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 0044b6853d..ce4b3d75ab 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -226,6 +226,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasXlabel_personX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().Has(T.Label,"person")}}, 
                {"g_V_hasXlabel_eqXpersonXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Has(T.Label,P.Eq("person"))}}, 
                {"g_V_hasXlabel_isXpersonXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Has(T.Label,__.Is("person"))}}, 
+               {"g_V_hasXname_nullX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name",(object) 
null)}}, 
                {"g_V_hasIdXemptyX_count", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().HasId(p["xx1"]).Count()}}, 
                {"g_V_hasIdXwithinXemptyXX_count", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
                {"g_V_hasIdXwithoutXemptyXX_count", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index e8f4f9b7fb..3a9378226d 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -197,6 +197,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_V_hasXlabel_personX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Has(gremlingo.T.Label, "person")}}, 
     "g_V_hasXlabel_eqXpersonXX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Has(gremlingo.T.Label, gremlingo.P.Eq("person"))}}, 
     "g_V_hasXlabel_isXpersonXX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Has(gremlingo.T.Label, gremlingo.T__.Is("person"))}}, 
+    "g_V_hasXname_nullX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", 
nil)}}, 
     "g_V_hasIdXemptyX_count": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().HasId(p["xx1"]).Count()}}, 
     "g_V_hasIdXwithinXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().HasId(p["xx1"]).Count()}}, 
     "g_V_hasIdXwithoutXemptyXX_count": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}}, 
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 fb8efe34c7..6b1fba4fb3 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
@@ -216,6 +216,7 @@ const gremlins = {
     g_V_hasXlabel_personX: [function({g}) { return g.V().has(T.label,"person") 
}], 
     g_V_hasXlabel_eqXpersonXX: [function({g}) { return 
g.V().has(T.label,P.eq("person")) }], 
     g_V_hasXlabel_isXpersonXX: [function({g}) { return 
g.V().has(T.label,__.is("person")) }], 
+    g_V_hasXname_nullX: [function({g}) { return g.V().has("name",null) }], 
     g_V_hasIdXemptyX_count: [function({g, xx1}) { return 
g.V().hasId(xx1).count() }], 
     g_V_hasIdXwithinXemptyXX_count: [function({g, xx1}) { return 
g.V().hasId(xx1).count() }], 
     g_V_hasIdXwithoutXemptyXX_count: [function({g, xx1}) { return 
g.V().hasId(xx1).count() }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index ba2c15fe97..84f373ca62 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -198,6 +198,7 @@ world.gremlins = {
     'g_V_hasXlabel_personX': [(lambda g:g.V().has(T.label,'person'))], 
     'g_V_hasXlabel_eqXpersonXX': [(lambda 
g:g.V().has(T.label,P.eq('person')))], 
     'g_V_hasXlabel_isXpersonXX': [(lambda 
g:g.V().has(T.label,__.is_('person')))], 
+    'g_V_hasXname_nullX': [(lambda g:g.V().has('name',None))], 
     'g_V_hasIdXemptyX_count': [(lambda g, xx1=None:g.V().hasId(xx1).count())], 
     'g_V_hasIdXwithinXemptyXX_count': [(lambda g, 
xx1=None:g.V().hasId(xx1).count())], 
     'g_V_hasIdXwithoutXemptyXX_count': [(lambda g, 
xx1=None:g.V().hasId(xx1).count())], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
index 1ae35324c6..aa71fcb4f0 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
@@ -611,4 +611,13 @@ Feature: Step - has()
       | v[marko] |
       | v[vadas] |
       | v[josh] |
-      | v[peter] |
\ No newline at end of file
+      | v[peter] |
+
+  Scenario: g_V_hasXname_nullX
+    Given the modern graph
+    And the traversal of
+    """
+    g.V().has("name", null)
+    """
+    When iterated to list
+    Then the result should be empty
\ No newline at end of file

Reply via email to