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 2019/09/09 14:31:05 UTC

[tinkerpop] branch TINKERPOP-2284 updated (051ae70 -> a557166)

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

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


 discard 051ae70  TINKERPOP-2284 wip
     new a557166  TINKERPOP-2284 Added elementMap() step

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (051ae70)
            \
             N -- N -- N   refs/heads/TINKERPOP-2284 (a557166)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

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.


Summary of changes:
 .../javascript/gremlin-javascript/lib/structure/io/type-serializers.js  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


[tinkerpop] 01/01: TINKERPOP-2284 Added elementMap() step

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

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

commit a5571663ffc6e637add47277c4ae4080e42ae30d
Author: Stephen Mallette <sp...@genoprime.com>
AuthorDate: Mon Sep 9 09:14:37 2019 -0400

    TINKERPOP-2284 Added elementMap() step
    
    Given that we only return reference objects for graph elements now, there is a lot of extra project()/valueMap() work to do for the simple and common need to return all the structure of a graph element. elementMap() simplifies all that to a single step without a ton of options and added features.
---
 CHANGELOG.asciidoc                                 |   3 +
 .../traversal/dsl/graph/GraphTraversal.java        |  27 ++-
 .../gremlin/process/traversal/dsl/graph/__.java    |   7 +
 .../process/traversal/step/map/ElementMapStep.java | 111 +++++++++++++
 .../org/apache/tinkerpop/gremlin/structure/T.java  |   8 +
 .../traversal/step/map/ElementMapStepTest.java     |  42 +++++
 .../Process/Traversal/GraphTraversal.cs            |  11 ++
 .../src/Gremlin.Net/Process/Traversal/__.cs        |  10 ++
 .../Structure/IO/GraphSON/DirectionDeserializer.cs |  36 ++++
 .../Structure/IO/GraphSON/GraphSONReader.cs        |   1 +
 .../Gherkin/CommonSteps.cs                         |  15 +-
 .../Structure/IO/GraphSON/GraphSONReaderTests.cs   |  12 ++
 .../lib/process/graph-traversal.js                 |  11 ++
 .../lib/structure/io/graph-serializer.js           |   1 +
 .../lib/structure/io/type-serializers.js           |   7 +
 .../test/cucumber/feature-steps.js                 |   8 +-
 .../gremlin_python/process/graph_traversal.py      |  14 ++
 .../gremlin_python/structure/io/graphsonV3d0.py    |  16 +-
 .../src/main/jython/radish/feature_steps.py        |   8 +-
 gremlin-test/features/map/ElementMap.feature       |  62 +++++++
 .../tinkerpop/gremlin/AbstractGremlinTest.java     |   4 +-
 .../gremlin/process/ProcessComputerSuite.java      |   3 +
 .../gremlin/process/ProcessStandardSuite.java      |   3 +
 .../process/traversal/step/map/ElementMapTest.java | 183 +++++++++++++++++++++
 24 files changed, 590 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 3d61b53..8ee342e 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -24,6 +24,9 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 === TinkerPop 3.4.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 
 * Provided support for DSLs by way of remote connections through `AnonymousTraversalSource`.
+* Added `elementMap()` step.
+* Allowed for embedded map assertions in GLV tests.
+* Added `Direction` deserialization support in GLVs.
 
 [[release-3-4-3]]
 === TinkerPop 3.4.3 (Release Date: August 5, 2019)
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 ce445c4..5a932c3 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
@@ -80,6 +80,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountLocalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.DedupLocalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeOtherVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -553,7 +554,26 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
-     * Map the {@link Element} to a {@link Map} of the property values key'd according to their {@link Property#key}.
+     * Map the {@link Element} to a {@code Map} of the property values key'd according to their {@link Property#key}.
+     * If no property keys are provided, then all property values are retrieved. For vertices, the {@code Map} will
+     * be returned with the assumption of single property values along with {@link T#id} and {@link T#label}. Prefer
+     * {@link #valueMap(String...)} if multi-property processing is required. For  edges, keys will include additional
+     * related edge structure of {@link Direction#IN} and {@link Direction#OUT} which themselves are {@code Map}
+     * instances of the particular {@link Vertex} represented by {@link T#id} and {@link T#label}.
+     *
+     * @param propertyKeys the properties to retrieve
+     * @param <E2>         the value type of the returned properties
+     * @return the traversal with an appended {@link ElementMapStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#elementmap-step" target="_blank">Reference Documentation - ElementMap Step</a>
+     * @since 3.4.4
+     */
+    public default <E2> GraphTraversal<S, Map<Object, E2>> elementMap(final String... propertyKeys) {
+        this.asAdmin().getBytecode().addStep(Symbols.elementMap, propertyKeys);
+        return this.asAdmin().addStep(new ElementMapStep<>(this.asAdmin(), propertyKeys));
+    }
+
+    /**
+     * Map the {@link Element} to a {@code Map} of the property values key'd according to their {@link Property#key}.
      * If no property keys are provided, then all property values are retrieved.
      *
      * @param propertyKeys the properties to retrieve
@@ -568,7 +588,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
-     * Map the {@link Element} to a {@link Map} of the property values key'd according to their {@link Property#key}.
+     * Map the {@link Element} to a {@code Map} of the property values key'd according to their {@link Property#key}.
      * If no property keys are provided, then all property values are retrieved.
      *
      * @param includeTokens whether to include {@link T} tokens in the emitted map.
@@ -578,7 +598,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#valuemap-step" target="_blank">Reference Documentation - ValueMap Step</a>
      * @since 3.0.0-incubating
      * @deprecated As of release 3.4.0, deprecated in favor of {@link GraphTraversal#valueMap(String...)} in conjunction with
-     *             {@link GraphTraversal#with(String, Object)}.
+     *             {@link GraphTraversal#with(String, Object)} or simple prefer {@link #elementMap(String...)}.
      */
     @Deprecated
     public default <E2> GraphTraversal<S, Map<Object, E2>> valueMap(final boolean includeTokens, final String... propertyKeys) {
@@ -2946,6 +2966,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         public static final String values = "values";
         public static final String propertyMap = "propertyMap";
         public static final String valueMap = "valueMap";
+        public static final String elementMap = "elementMap";
         public static final String select = "select";
         public static final String key = "key";
         public static final String value = "value";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index ab98930..aab83f4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -254,6 +254,13 @@ public class __ {
     }
 
     /**
+     * @see GraphTraversal#elementMap(String...)
+     */
+    public static <A extends Element, B> GraphTraversal<A, Map<Object, B>> elementMap(final String... propertyKeys) {
+        return __.<A>start().elementMap(propertyKeys);
+    }
+
+    /**
      * @see GraphTraversal#valueMap(String...)
      */
     public static <A extends Element, B> GraphTraversal<A, Map<Object, B>> valueMap(final String... propertyKeys) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
new file mode 100644
index 0000000..c2a2c76
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Converts a {@link Element} to a {@code Map}.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class ElementMapStep<K,E> extends MapStep<Element, Map<K, E>> implements TraversalParent {
+
+    protected final String[] propertyKeys;
+
+    public ElementMapStep(final Traversal.Admin traversal, final String... propertyKeys) {
+        super(traversal);
+        this.propertyKeys = propertyKeys;
+    }
+
+    @Override
+    protected Map<K, E> map(final Traverser.Admin<Element> traverser) {
+        final Map<Object, Object> map = new LinkedHashMap<>();
+        final Element element = traverser.get();
+        map.put(T.id, element.id());
+        if (element instanceof VertexProperty) {
+            map.put(T.key, ((VertexProperty<?>) element).key());
+            map.put(T.value, ((VertexProperty<?>) element).value());
+        } else {
+            map.put(T.label, element.label());
+        }
+
+        if (element instanceof Edge) {
+            final Edge e = (Edge) element;
+            map.put(Direction.IN, getVertexStructure(e.inVertex()));
+            map.put(Direction.OUT, getVertexStructure(e.outVertex()));
+        }
+
+        final Iterator<? extends Property> properties = element.properties(this.propertyKeys);
+        while (properties.hasNext()) {
+            final Property<?> property = properties.next();
+            map.put(property.key(), property.value());
+        }
+
+        return (Map) map;
+    }
+
+    protected Map<Object, Object> getVertexStructure(final Vertex v) {
+        final Map<Object, Object> m = new LinkedHashMap<>();
+        m.put(T.id, v.id());
+        m.put(T.label, v.label());
+        return m;
+    }
+
+    public String[] getPropertyKeys() {
+        return propertyKeys;
+    }
+
+    public String toString() {
+        return StringFactory.stepString(this, Arrays.asList(this.propertyKeys));
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        for (final String propertyKey : this.propertyKeys) {
+            result ^= propertyKey.hashCode();
+        }
+        return result;
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/T.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/T.java
index a836840..2d67d6b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/T.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/T.java
@@ -30,6 +30,8 @@ import java.util.function.Function;
 public enum T implements Function<Element, Object> {
     /**
      * Label (representing Element.label())
+     *
+     * @since 3.0.0-incubating
      */
     label {
         @Override
@@ -44,6 +46,8 @@ public enum T implements Function<Element, Object> {
     },
     /**
      * Id (representing Element.id())
+     *
+     * @since 3.0.0-incubating
      */
     id {
         @Override
@@ -58,6 +62,8 @@ public enum T implements Function<Element, Object> {
     },
     /**
      * Key (representing Property.key())
+     *
+     * @since 3.0.0-incubating
      */
     key {
         @Override
@@ -72,6 +78,8 @@ public enum T implements Function<Element, Object> {
     },
     /**
      * Value (representing Property.value())
+     *
+     * @since 3.0.0-incubating
      */
     value {
         @Override
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStepTest.java
new file mode 100644
index 0000000..3bffbe0
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStepTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class ElementMapStepTest extends StepTest {
+
+    @Override
+    protected List<Traversal> getTraversals() {
+        return Arrays.asList(
+                __.elementMap(),
+                __.elementMap("name"),
+                __.elementMap("age"),
+                __.elementMap("name", "age")
+        );
+    }
+}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index f22ee8c..f65276b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -487,6 +487,17 @@ namespace Gremlin.Net.Process.Traversal
         }
 
         /// <summary>
+        ///     Adds the elementMap step to this <see cref="GraphTraversal{SType, EType}" />.
+        /// </summary>
+        public GraphTraversal<S, IDictionary<object, E2>> ElementMap<E2> (params string[] propertyKeys)
+        {
+            var args = new List<object>(0 + propertyKeys.Length) {};
+            args.AddRange(propertyKeys);
+            Bytecode.AddStep("elementMap", args.ToArray());
+            return Wrap<S, IDictionary<object, E2>>(this);
+        }
+
+        /// <summary>
         ///     Adds the emit step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
         public GraphTraversal<S, E> Emit ()
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index af31d1b..9bd0b14 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -331,6 +331,16 @@ namespace Gremlin.Net.Process.Traversal
         }
 
         /// <summary>
+        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the elementMap step to that traversal.
+        /// </summary>
+        public static GraphTraversal<object, IDictionary<object, E2>> ElementMap<E2>(params string[] propertyKeys)
+        {
+            return propertyKeys.Length == 0
+                ? new GraphTraversal<object, IDictionary<object, E2>>().ElementMap<E2>()
+                : new GraphTraversal<object, IDictionary<object, E2>>().ElementMap<E2>(propertyKeys);            
+        }
+
+        /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the emit step to that traversal.
         /// </summary>
         public static GraphTraversal<object, object> Emit()
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs
new file mode 100644
index 0000000..4027171
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DirectionDeserializer.cs
@@ -0,0 +1,36 @@
+#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 Gremlin.Net.Process.Traversal;
+using Newtonsoft.Json.Linq;
+
+namespace Gremlin.Net.Structure.IO.GraphSON
+{
+    internal class DirectionDeserializer : IGraphSONDeserializer
+    {
+        public dynamic Objectify(JToken graphsonObject, GraphSONReader reader)
+        {
+            return Direction.GetByValue(graphsonObject.ToString());
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
index 5ced99a..63641f0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
@@ -44,6 +44,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
                 {"g:Int64", new Int64Converter()},
                 {"g:Float", new FloatConverter()},
                 {"g:Double", new DoubleConverter()},
+                {"g:Direction", new DirectionDeserializer()},
                 {"g:UUID", new UuidDeserializer()},
                 {"g:Date", new DateDeserializer()},
                 {"g:Timestamp", new DateDeserializer()},
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
index 96851d2..1c6588b 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -51,6 +51,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             new Dictionary<string, Func<string, string, object>>
             {
                 {@"d\[([\d.]+)\]\.([ilfdm])", ToNumber},
+                {@"D\[(.+)\]", ToDirection},
                 {@"v\[(.+)\]", ToVertex},
                 {@"v\[(.+)\]\.id", (x, graphName) => ToVertex(x, graphName).Id},
                 {@"v\[(.+)\]\.sid", (x, graphName) => ToVertex(x, graphName).Id.ToString()},
@@ -90,7 +91,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
         [Given("using the parameter (\\w+) defined as \"(.*)\"")]
         public void UsingParameter(string name, string value)
         {
-            var parsedValue = ParseValue(value, _graphName);
+            var parsedValue = ParseValue(value.Replace("\\\"", "\""), _graphName);
             _parameters.Add(name, parsedValue);
         }
 
@@ -244,6 +245,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             return T.GetByValue(enumName);
         }
 
+        private static object ToDirection(string enumName, string graphName)
+        {
+            return Direction.GetByValue(enumName);
+        }
+
+//        private static string toNormalCase(string name)
+//        {
+//            return name.Substring(0, 1) + name.Substring(1).ToLower();
+//        }
+
         private static object ToNumber(string stringNumber, string graphName)
         {
             return NumericParsers[stringNumber[stringNumber.Length - 1]](
@@ -306,8 +317,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
 
         private static object ParseValue(string stringValue, string graphName)
         {
-            // Parser issue: quotes are not normalized
-            stringValue = stringValue.Replace("\\\"", "\"");
             Func<string, string, object> parser = null;
             string extractedValue = null;
             foreach (var kv in Parsers)
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 7685b28..3a49143 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
@@ -280,6 +280,18 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
             Assert.Equal(T.Label, readT);
         }
 
+        [Theory, MemberData(nameof(Versions))]
+        public void ShouldDeserializeDirection(int version)
+        {
+            var serializedValue = "{\"@type\":\"g:Direction\",\"@value\":\"OUT\"}";
+            var reader = CreateStandardGraphSONReader(version);
+
+            var jObject = JObject.Parse(serializedValue);
+            var deserializedValue = reader.ToObject(jObject);
+
+            Assert.Equal(Direction.Out, deserializedValue);
+        }
+
         [Fact]
         public void ShouldDeserializePathFromGraphSON2()
         {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
index 157b0af..0fe34d6 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
@@ -443,6 +443,16 @@ class GraphTraversal extends Traversal {
   }
   
   /**
+   * Graph traversal elementMap method.
+   * @param {...Object} args
+   * @returns {GraphTraversal}
+   */
+  elementMap(...args) {
+    this.bytecode.addStep('elementMap', args);
+    return this;
+  }
+  
+  /**
    * Graph traversal emit method.
    * @param {...Object} args
    * @returns {GraphTraversal}
@@ -1264,6 +1274,7 @@ const statics = {
   cyclicPath: (...args) => callOnEmptyTraversal('cyclicPath', args),
   dedup: (...args) => callOnEmptyTraversal('dedup', args),
   drop: (...args) => callOnEmptyTraversal('drop', args),
+  elementMap: (...args) => callOnEmptyTraversal('elementMap', args),
   emit: (...args) => callOnEmptyTraversal('emit', args),
   filter: (...args) => callOnEmptyTraversal('filter', args),
   flatMap: (...args) => callOnEmptyTraversal('flatMap', args),
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
index ff14320..7943852 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
@@ -163,6 +163,7 @@ const deserializers = {
   'g:Float':  typeSerializers.NumberSerializer,
   'g:Double': typeSerializers.NumberSerializer,
   'g:Date': typeSerializers.DateSerializer,
+  'g:Direction': typeSerializers.DirectionSerializer,
   'g:Vertex': typeSerializers.VertexSerializer,
   'g:Edge': typeSerializers.EdgeSerializer,
   'g:VertexProperty': typeSerializers.VertexPropertySerializer,
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
index cfd67c9..fb950c8 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
@@ -363,6 +363,12 @@ class TSerializer extends TypeSerializer {
   }
 }
 
+class DirectionSerializer extends TypeSerializer {
+    deserialize(obj) {
+        return t.direction[obj[valueKey].toLowerCase()];
+    }
+}
+
 class ArraySerializer extends TypeSerializer {
   constructor(typeKey) {
     super();
@@ -458,6 +464,7 @@ module.exports = {
   BulkSetSerializer,
   BytecodeSerializer,
   DateSerializer,
+  DirectionSerializer,
   EdgeSerializer,
   EnumSerializer,
   LambdaSerializer,
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
index 02e7b3f..fed551d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
@@ -34,6 +34,7 @@ const traversal = require('../../lib/process/anonymous-traversal').traversal;
 const Path = graphModule.Path;
 const __ = graphTraversalModule.statics;
 const t = traversalModule.t;
+const direction = traversalModule.direction
 
 // Determines whether the feature maps (m[]), are deserialized as objects (true) or maps (false).
 // Use false for GraphSON3.
@@ -52,7 +53,8 @@ const parsers = [
   [ 's\\[(.*)\\]', toArray ],
   [ 'm\\[(.+)\\]', toMap ],
   [ 'c\\[(.+)\\]', toLambda ],
-  [ 't\\[(.+)\\]', toT ]
+  [ 't\\[(.+)\\]', toT ],
+  [ 'D\\[(.+)\\]', toDirection ]
 ].map(x => [ new RegExp('^' + x[0] + '$'), x[1] ]);
 
 const ignoreReason = {
@@ -276,6 +278,10 @@ function toT(value) {
   return t[value];
 }
 
+function toDirection(value) {
+    return direction[value.toLowerCase()];
+}
+
 function toArray(stringList) {
   if (stringList === '') {
     return new Array(0);
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py
index 5dde030..4be02f8 100644
--- a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py
+++ b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py
@@ -229,6 +229,10 @@ class GraphTraversal(Traversal):
         self.bytecode.add_step("drop", *args)
         return self
 
+    def elementMap(self, *args):
+        self.bytecode.add_step("elementMap", *args)
+        return self
+
     def emit(self, *args):
         self.bytecode.add_step("emit", *args)
         return self
@@ -664,6 +668,10 @@ class __(object):
         return cls.graph_traversal(None, None, Bytecode()).drop(*args)
 
     @classmethod
+    def elementMap(cls, *args):
+        return cls.graph_traversal(None, None, Bytecode()).elementMap(*args)
+
+    @classmethod
     def emit(cls, *args):
         return cls.graph_traversal(None, None, Bytecode()).emit(*args)
 
@@ -1046,6 +1054,10 @@ def drop(*args):
     return __.drop(*args)
 
 
+def elementMap(*args):
+    return __.elementMap(*args)
+
+
 def emit(*args):
     return __.emit(*args)
 
@@ -1388,6 +1400,8 @@ statics.add_static('dedup', dedup)
 
 statics.add_static('drop', drop)
 
+statics.add_static('elementMap', elementMap)
+
 statics.add_static('emit', emit)
 
 statics.add_static('filter_', filter_)
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py
index 8c3cd9f..bccb982 100644
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py
+++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py
@@ -34,7 +34,7 @@ from isodate import parse_duration, duration_isoformat
 
 from gremlin_python import statics
 from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar
-from gremlin_python.process.traversal import Binding, Bytecode, P, TextP, Traversal, Traverser, TraversalStrategy, T
+from gremlin_python.process.traversal import Binding, Bytecode, Direction, P, TextP, Traversal, Traverser, TraversalStrategy, T
 from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
 
 log = logging.getLogger(__name__)
@@ -711,6 +711,20 @@ class TDeserializer(_GraphSONTypeIO):
     def objectify(cls, d, reader):
         return T[d]
 
+
+class DirectionIO(_GraphSONTypeIO):
+    graphson_type = "g:Direction"
+    graphson_base_type = "Direction"
+    python_type = Direction
+
+    @classmethod
+    def dictify(cls, d, writer):
+        return GraphSONUtil.typedValue(cls.graphson_base_type, d.name, "g")
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Direction[d]
+
 class TraversalMetricsDeserializer(_GraphSONTypeIO):
     graphson_type = "g:TraversalMetrics"
 
diff --git a/gremlin-python/src/main/jython/radish/feature_steps.py b/gremlin-python/src/main/jython/radish/feature_steps.py
index ed6c15d..8db6b7b 100644
--- a/gremlin-python/src/main/jython/radish/feature_steps.py
+++ b/gremlin-python/src/main/jython/radish/feature_steps.py
@@ -80,7 +80,7 @@ def add_parameter(step, param_name, param):
     if not hasattr(step.context, "traversal_params"):
         step.context.traversal_params = {}
 
-    step.context.traversal_params[param_name] = _convert(param, step.context)
+    step.context.traversal_params[param_name] = _convert(param.replace('\\"', '"'), step.context)
 
 
 @given("the traversal of")
@@ -172,14 +172,16 @@ def _convert(val, ctx):
     elif isinstance(val, str) and re.match("^e\[.*\]$", val):           # parse edge
         return __find_cached_element(ctx, graph_name, val[2:-1], "e")
     elif isinstance(val, str) and re.match("^m\[.*\]$", val):           # parse json as a map
-        return _convert(json.loads(val[2:-1].replace('\\"', '"')), ctx)
+        return _convert(json.loads(val[2:-1]), ctx)
     elif isinstance(val, str) and re.match("^p\[.*\]$", val):           # parse path
         path_objects = list(map((lambda x: _convert(x, ctx)), val[2:-1].split(",")))
         return Path([set([])], path_objects)
     elif isinstance(val, str) and re.match("^c\[.*\]$", val):           # parse lambda/closure
         return lambda: (val[2:-1], "gremlin-groovy")
-    elif isinstance(val, str) and re.match("^t\[.*\]$", val):         # parse instance of T enum
+    elif isinstance(val, str) and re.match("^t\[.*\]$", val):           # parse instance of T enum
         return T[val[2:-1]]
+    elif isinstance(val, str) and re.match("^D\[.*\]$", val):           # parse instance of Direction enum
+        return Direction[val[2:-1]]
     else:
         return val
 
diff --git a/gremlin-test/features/map/ElementMap.feature b/gremlin-test/features/map/ElementMap.feature
new file mode 100644
index 0000000..95de688
--- /dev/null
+++ b/gremlin-test/features/map/ElementMap.feature
@@ -0,0 +1,62 @@
+# 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.
+
+Feature: Step - elementMap()
+
+  Scenario: g_V_elementMap
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().elementMap()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"t[id]": "v[marko].id", "t[label]": "person", "name": "marko", "age": 29}] |
+      | m[{"t[id]": "v[josh].id", "t[label]": "person", "name": "josh", "age": 32}] |
+      | m[{"t[id]": "v[peter].id", "t[label]": "person", "name": "peter", "age": 35}] |
+      | m[{"t[id]": "v[vadas].id", "t[label]": "person", "name": "vadas", "age": 27}] |
+      | m[{"t[id]": "v[lop].id", "t[label]": "software", "name": "lop", "lang": "java"}] |
+      | m[{"t[id]": "v[ripple].id", "t[label]": "software", "name": "ripple", "lang": "java"}] |
+
+  Scenario: g_V_elementMapXname_ageX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().elementMap("name", "age")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"t[id]": "v[marko].id", "t[label]": "person", "name": "marko", "age": 29}] |
+      | m[{"t[id]": "v[josh].id", "t[label]": "person", "name": "josh", "age": 32}] |
+      | m[{"t[id]": "v[peter].id", "t[label]": "person", "name": "peter", "age": 35}] |
+      | m[{"t[id]": "v[vadas].id", "t[label]": "person", "name": "vadas", "age": 27}] |
+      | m[{"t[id]": "v[lop].id", "t[label]": "software", "name": "lop"}] |
+      | m[{"t[id]": "v[ripple].id", "t[label]": "software", "name": "ripple"}] |
+
+  Scenario: g_EX11X_elementMap
+    Given the modern graph
+    And using the parameter e11Id defined as "e[josh-created->lop].id"
+    And the traversal of
+    """
+      g.E(e11Id).elementMap()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | m[{"t[id]": "e[josh-created->lop].id", "t[label]": "created", "weight": "d[0.4].d", "D[OUT]": "m[{\\"t[id]\\": \\"v[josh].id\\", \\"t[label]\\": \\"person\\"}]", "D[IN]": "m[{\\"t[id]\\": \\"v[lop].id\\", \\"t[label]\\": \\"software\\"}]"}] |
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
index 650dd38..f069a12 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java
@@ -159,8 +159,8 @@ public abstract class AbstractGremlinTest {
                 logger.warn("The {} is not of type ManagedGraphProvider and therefore graph instances may leak between test cases.", graphProvider.getClass());
 
             if (shouldTestIteratorLeak) {
-                long wait = 300;
-                long[] tries = new long[] { 1, 3, 5, 7, 9, 18, 27, 36, 72, 144, 256, 512 };
+                final long wait = 300;
+                final long[] tries = new long[] { 1, 3, 5, 7, 9, 18, 27, 36, 72, 144, 256, 512 };
                 long openItrCount = StoreIteratorCounter.INSTANCE.getOpenIteratorCount();
                 for (int ix = 0; ix < tries.length && openItrCount > 0; ix++) {
                     Thread.sleep(wait * tries[ix]);
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
index 0951b86..3ca5b76 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
@@ -54,6 +54,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.CoalesceTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConnectedComponentTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConstantTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountTest;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FlatMapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphTest;
@@ -150,6 +151,7 @@ public class ProcessComputerSuite extends AbstractGremlinSuite {
             ConnectedComponentTest.Traversals.class,
             ConstantTest.Traversals.class,
             CountTest.Traversals.class,
+            ElementMapTest.Traversals.class,
             FlatMapTest.Traversals.class,
             FoldTest.Traversals.class,
             GraphTest.Traversals.class,
@@ -249,6 +251,7 @@ public class ProcessComputerSuite extends AbstractGremlinSuite {
             ConstantTest.class,
             CountTest.class,
             FlatMapTest.class,
+            ElementMapTest.class,
             FoldTest.class,
             MatchTest.class,
             MathTest.class,
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
index 6bd6d5b..f127ca0 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
@@ -48,6 +48,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CoalesceTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConstantTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountTest;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FlatMapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphTest;
@@ -140,6 +141,7 @@ public class ProcessStandardSuite extends AbstractGremlinSuite {
             CoalesceTest.Traversals.class,
             ConstantTest.Traversals.class,
             CountTest.Traversals.class,
+            ElementMapTest.Traversals.class,
             FlatMapTest.Traversals.class,
             FoldTest.Traversals.class,
             GraphTest.Traversals.class,
@@ -232,6 +234,7 @@ public class ProcessStandardSuite extends AbstractGremlinSuite {
             CoalesceTest.class,
             ConstantTest.class,
             CountTest.class,
+            ElementMapTest.class,
             FlatMapTest.class,
             FoldTest.class,
             LoopsTest.class,
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapTest.java
new file mode 100644
index 0000000..d64cbd9
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
+import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW;
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.apache.tinkerpop.gremlin.structure.T.id;
+import static org.apache.tinkerpop.gremlin.structure.T.label;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(GremlinProcessRunner.class)
+public abstract class ElementMapTest extends AbstractGremlinProcessTest {
+
+    public abstract Traversal<Vertex, Map<Object, Object>> get_g_V_elementMap();
+
+    public abstract Traversal<Vertex, Map<Object, Object>> get_g_V_elementMapXname_ageX();
+
+    public abstract Traversal<Edge, Map<Object, Object>> get_g_EX11X_elementMap(final Object e11Id);
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_elementMap() {
+        final Traversal<Vertex, Map<Object, Object>> traversal = get_g_V_elementMap();
+        printTraversalForm(traversal);
+        int counter = 0;
+        while (traversal.hasNext()) {
+            counter++;
+            final Map<Object, Object> values = traversal.next();
+            final String name = (String) values.get("name");
+            assertEquals(4, values.size());
+            if (name.equals("marko")) {
+                assertEquals(29, values.get("age"));
+                assertEquals("person", values.get(label));
+            } else if (name.equals("josh")) {
+                assertEquals(32, values.get("age"));
+                assertEquals("person", values.get(label));
+            } else if (name.equals("peter")) {
+                assertEquals(35, values.get("age"));
+                assertEquals("person", values.get(label));
+            } else if (name.equals("vadas")) {
+                assertEquals(27, values.get("age"));
+                assertEquals("person", values.get(label));
+            } else if (name.equals("lop")) {
+                assertEquals("java", values.get("lang"));
+                assertEquals("software", values.get(label));
+            } else if (name.equals("ripple")) {
+                assertEquals("java", values.get("lang"));
+                assertEquals("software", values.get(label));
+            } else {
+                throw new IllegalStateException("It is not possible to reach here: " + values);
+            }
+
+            assertThat(values.containsKey(T.id), is(true));
+        }
+        assertEquals(6, counter);
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_elementMapXname_ageX() {
+        final Traversal<Vertex, Map<Object, Object>> traversal = get_g_V_elementMapXname_ageX();
+        printTraversalForm(traversal);
+        int counter = 0;
+        while (traversal.hasNext()) {
+            counter++;
+            final Map<Object, Object> values = traversal.next();
+            final String name = (String) values.get("name");
+            if (name.equals("marko")) {
+                assertEquals(29, values.get("age"));
+                assertEquals("person", values.get(label));
+                assertEquals(4, values.size());
+            } else if (name.equals("josh")) {
+                assertEquals(32, values.get("age"));
+                assertEquals("person", values.get(label));
+                assertEquals(4, values.size());
+            } else if (name.equals("peter")) {
+                assertEquals(35, values.get("age"));
+                assertEquals("person", values.get(label));
+                assertEquals(4, values.size());
+            } else if (name.equals("vadas")) {
+                assertEquals(27, values.get("age"));
+                assertEquals("person", values.get(label));
+                assertEquals(4, values.size());
+            } else if (name.equals("lop")) {
+                assertNull(values.get("lang"));
+                assertEquals("software", values.get(label));
+                assertEquals(3, values.size());
+            } else if (name.equals("ripple")) {
+                assertNull(values.get("lang"));
+                assertEquals("software", values.get(label));
+                assertEquals(3, values.size());
+            } else {
+                throw new IllegalStateException("It is not possible to reach here: " + values);
+            }
+
+            assertThat(values.containsKey(T.id), is(true));
+        }
+        assertEquals(6, counter);
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_EX11X_elementMap() {
+        final Object edgeId = convertToEdgeId("josh", "created", "lop");
+        final Traversal<Edge, Map<Object,Object>> traversal = get_g_EX11X_elementMap(edgeId);
+        printTraversalForm(traversal);
+
+        final Map<Object,Object> m = traversal.next();
+        assertEquals(5, m.size());
+        assertEquals(0.4d, m.get("weight"));
+        assertEquals("created", m.get(label));
+        assertEquals(edgeId, m.get(T.id));
+
+        final Vertex vJosh = convertToVertex("josh");
+        assertEquals(vJosh.id(), ((Map<Object,Object>) m.get(Direction.OUT)).get(T.id));
+        assertEquals(vJosh.label(), ((Map<Object,Object>) m.get(Direction.OUT)).get(T.label));
+
+        final Vertex vLop = convertToVertex("lop");
+        assertEquals(vLop.id(), ((Map<Object,Object>) m.get(Direction.IN)).get(T.id));
+        assertEquals(vLop.label(), ((Map<Object,Object>) m.get(Direction.IN)).get(T.label));
+
+        assertThat(traversal.hasNext(), is(false));
+    }
+
+    public static class Traversals extends ElementMapTest {
+        @Override
+        public Traversal<Vertex, Map<Object, Object>> get_g_V_elementMap() {
+            return g.V().elementMap();
+        }
+
+        @Override
+        public Traversal<Vertex, Map<Object, Object>> get_g_V_elementMapXname_ageX() {
+            return g.V().elementMap("name", "age");
+        }
+
+        @Override
+        public Traversal<Edge, Map<Object, Object>> get_g_EX11X_elementMap(final Object e11Id) {
+            return g.E(e11Id).elementMap();
+        }
+    }
+}