You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by jo...@apache.org on 2021/07/07 00:06:58 UTC

[tinkerpop] 03/04: Add a runnable example of a Thrift client sending graphs to a server over TChannel

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

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

commit bb3a01b816234e309e659c7444a343d912e204bc
Author: Joshua Shinavier <jo...@uber.com>
AuthorDate: Tue Jul 6 17:02:56 2021 -0700

    Add a runnable example of a Thrift client sending graphs to a server over TChannel
---
 .../examples/graphs-over-thrift/.gitignore         |    5 +
 .../examples/graphs-over-thrift/README.md          |   42 +
 .../examples/graphs-over-thrift/build.gradle       |   41 +
 .../examples/graphs-over-thrift/dragon.yaml        |    5 +
 .../examples/graphs-over-thrift/gradlew            |  185 ++++
 .../examples/graphs-over-thrift/settings.gradle    |    1 +
 .../examples/thrift/AddGraphException.java         |  375 +++++++
 .../language/examples/thrift/AddGraphResponse.java |  466 +++++++++
 .../language/examples/thrift/ExampleService.java   | 1098 ++++++++++++++++++++
 .../language/property_graphs/AtomicValue.java      |  757 ++++++++++++++
 .../gremlin/language/property_graphs/Edge.java     |  940 +++++++++++++++++
 .../gremlin/language/property_graphs/Graph.java    |  624 +++++++++++
 .../gremlin/language/property_graphs/Property.java |  690 ++++++++++++
 .../gremlin/language/property_graphs/Value.java    |  829 +++++++++++++++
 .../gremlin/language/property_graphs/Vertex.java   |  704 +++++++++++++
 .../gremlin/language/property_graphs.thrift        |  248 +++++
 .../language/examples/thrift/AddGraphHandler.java  |   83 ++
 .../examples/thrift/ExampleGraphClient.java        |   41 +
 .../examples/thrift/ExampleGraphServer.java        |   38 +
 .../language/examples/thrift/GraphThriftUtils.java |  190 ++++
 .../src/main/thrift/graphs_over_thrift.thrift      |   16 +
 .../gremlin/language/property_graphs.yaml          |    2 +-
 22 files changed, 7379 insertions(+), 1 deletion(-)

diff --git a/gremlin-language/examples/graphs-over-thrift/.gitignore b/gremlin-language/examples/graphs-over-thrift/.gitignore
new file mode 100644
index 0000000..1b6985c
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/.gitignore
@@ -0,0 +1,5 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
diff --git a/gremlin-language/examples/graphs-over-thrift/README.md b/gremlin-language/examples/graphs-over-thrift/README.md
new file mode 100644
index 0000000..456bb34
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/README.md
@@ -0,0 +1,42 @@
+This directory contains a complete example of a small graph being constructed by a client
+and sent to a server using Thrift over TChannel.
+
+## Running the demo
+
+Start the server:
+
+```bash
+gradle runServer
+```
+
+In a separate terminal, run the client.
+Remove the previously generated GraphSON file, first,
+if this is not the first time you are running the demo:
+
+```bash
+rm /tmp/graphs-over-thrift.json
+
+gradle runClient
+```
+
+You should now see a new GraphSON file, `/tmp/graphs-over-thrift.json`.
+This is a reconstituted version of the graph which is constructed by the client (see `ExampleGraphClient.java`).
+
+## Generating sources
+
+Some of the sources in this directory are hand-written, while others are generated.
+Follow the steps below in order to re-created all of the generated sources.
+Note: the first step requires Dragon, which is a proprietary tool.
+
+### Generate property_graphs.thrift:
+
+```bash
+dragon transform -o Thrift -i YAML ../../src/main/yaml -d org/apache/tinkerpop/gremlin/language/property_graphs.yaml src/gen/thrift
+```
+
+### Generate client/server Java:
+
+```bash
+thrift --gen java -out src/gen/java src/gen/thrift/org/apache/tinkerpop/gremlin/language/property_graphs.thrift
+thrift --gen java -out src/gen/java src/main/thrift/graphs_over_thrift.thrift
+```
diff --git a/gremlin-language/examples/graphs-over-thrift/build.gradle b/gremlin-language/examples/graphs-over-thrift/build.gradle
new file mode 100644
index 0000000..f3d93c3
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/build.gradle
@@ -0,0 +1,41 @@
+plugins {
+    id 'java'
+//    id 'application'
+}
+
+apply plugin : 'java'
+
+sourceSets {
+    main {
+        java {
+            srcDirs = ['src/main/java', 'src/gen/java']
+        }
+    }
+}
+
+//ext {
+//    javaMainClass = "org.apache.tinkerpop.gremlin.language.examples.thrift.ExampleGraphServer"
+//}
+//
+//application {
+//    mainClassName = javaMainClass
+//}
+
+dependencies {
+    implementation 'org.apache.thrift:libthrift:0.14.0'
+    implementation 'org.apache.tinkerpop:tinkergraph-gremlin:3.5.0'
+}
+
+repositories {
+    mavenCentral()
+}
+
+task(runClient, dependsOn: 'classes', type: JavaExec) {
+    main = 'org.apache.tinkerpop.gremlin.language.examples.thrift.ExampleGraphClient'
+    classpath = sourceSets.main.runtimeClasspath
+}
+
+task(runServer, dependsOn: 'classes', type: JavaExec) {
+    main = 'org.apache.tinkerpop.gremlin.language.examples.thrift.ExampleGraphServer'
+    classpath = sourceSets.main.runtimeClasspath
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/dragon.yaml b/gremlin-language/examples/graphs-over-thrift/dragon.yaml
new file mode 100644
index 0000000..c17c394
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/dragon.yaml
@@ -0,0 +1,5 @@
+jvm:
+  # Java package names will begin with this prefix. For example, if a schema has the name "foo/bar", the
+  # corresponding Java package name in Thrift will be "org.example.foo.bar".
+  namespacePrefix: ""
+
diff --git a/gremlin-language/examples/graphs-over-thrift/gradlew b/gremlin-language/examples/graphs-over-thrift/gradlew
new file mode 100755
index 0000000..4f906e0
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed 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
+#
+#      https://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.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gremlin-language/examples/graphs-over-thrift/settings.gradle b/gremlin-language/examples/graphs-over-thrift/settings.gradle
new file mode 100644
index 0000000..97c50da
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'graphs-over-thrift'
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphException.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphException.java
new file mode 100644
index 0000000..d599ff6
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphException.java
@@ -0,0 +1,375 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class AddGraphException extends org.apache.thrift.TException implements org.apache.thrift.TBase<AddGraphException, AddGraphException._Fields>, java.io.Serializable, Cloneable, Comparable<AddGraphException> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AddGraphException");
+
+  private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)1);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new AddGraphExceptionStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new AddGraphExceptionTupleSchemeFactory();
+
+  public @org.apache.thrift.annotation.Nullable java.lang.String message; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    MESSAGE((short)1, "message");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // MESSAGE
+          return MESSAGE;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AddGraphException.class, metaDataMap);
+  }
+
+  public AddGraphException() {
+  }
+
+  public AddGraphException(
+    java.lang.String message)
+  {
+    this();
+    this.message = message;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public AddGraphException(AddGraphException other) {
+    if (other.isSetMessage()) {
+      this.message = other.message;
+    }
+  }
+
+  public AddGraphException deepCopy() {
+    return new AddGraphException(this);
+  }
+
+  @Override
+  public void clear() {
+    this.message = null;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getMessage() {
+    return this.message;
+  }
+
+  public AddGraphException setMessage(@org.apache.thrift.annotation.Nullable java.lang.String message) {
+    this.message = message;
+    return this;
+  }
+
+  public void unsetMessage() {
+    this.message = null;
+  }
+
+  /** Returns true if field message is set (has been assigned a value) and false otherwise */
+  public boolean isSetMessage() {
+    return this.message != null;
+  }
+
+  public void setMessageIsSet(boolean value) {
+    if (!value) {
+      this.message = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case MESSAGE:
+      if (value == null) {
+        unsetMessage();
+      } else {
+        setMessage((java.lang.String)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case MESSAGE:
+      return getMessage();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case MESSAGE:
+      return isSetMessage();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof AddGraphException)
+      return this.equals((AddGraphException)that);
+    return false;
+  }
+
+  public boolean equals(AddGraphException that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_message = true && this.isSetMessage();
+    boolean that_present_message = true && that.isSetMessage();
+    if (this_present_message || that_present_message) {
+      if (!(this_present_message && that_present_message))
+        return false;
+      if (!this.message.equals(that.message))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287);
+    if (isSetMessage())
+      hashCode = hashCode * 8191 + message.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(AddGraphException other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetMessage(), other.isSetMessage());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMessage()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("AddGraphException(");
+    boolean first = true;
+
+    sb.append("message:");
+    if (this.message == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.message);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class AddGraphExceptionStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AddGraphExceptionStandardScheme getScheme() {
+      return new AddGraphExceptionStandardScheme();
+    }
+  }
+
+  private static class AddGraphExceptionStandardScheme extends org.apache.thrift.scheme.StandardScheme<AddGraphException> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, AddGraphException struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // MESSAGE
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.message = iprot.readString();
+              struct.setMessageIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, AddGraphException struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.message != null) {
+        oprot.writeFieldBegin(MESSAGE_FIELD_DESC);
+        oprot.writeString(struct.message);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class AddGraphExceptionTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AddGraphExceptionTupleScheme getScheme() {
+      return new AddGraphExceptionTupleScheme();
+    }
+  }
+
+  private static class AddGraphExceptionTupleScheme extends org.apache.thrift.scheme.TupleScheme<AddGraphException> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, AddGraphException struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetMessage()) {
+        optionals.set(0);
+      }
+      oprot.writeBitSet(optionals, 1);
+      if (struct.isSetMessage()) {
+        oprot.writeString(struct.message);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, AddGraphException struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet incoming = iprot.readBitSet(1);
+      if (incoming.get(0)) {
+        struct.message = iprot.readString();
+        struct.setMessageIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphResponse.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphResponse.java
new file mode 100644
index 0000000..9e0b507
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphResponse.java
@@ -0,0 +1,466 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class AddGraphResponse implements org.apache.thrift.TBase<AddGraphResponse, AddGraphResponse._Fields>, java.io.Serializable, Cloneable, Comparable<AddGraphResponse> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AddGraphResponse");
+
+  private static final org.apache.thrift.protocol.TField TOTAL_VERTICES_AFTER_OPERATION_FIELD_DESC = new org.apache.thrift.protocol.TField("totalVerticesAfterOperation", org.apache.thrift.protocol.TType.I64, (short)1);
+  private static final org.apache.thrift.protocol.TField TOTAL_EDGES_AFTER_OPERATION_FIELD_DESC = new org.apache.thrift.protocol.TField("totalEdgesAfterOperation", org.apache.thrift.protocol.TType.I64, (short)2);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new AddGraphResponseStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new AddGraphResponseTupleSchemeFactory();
+
+  public long totalVerticesAfterOperation; // required
+  public long totalEdgesAfterOperation; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    TOTAL_VERTICES_AFTER_OPERATION((short)1, "totalVerticesAfterOperation"),
+    TOTAL_EDGES_AFTER_OPERATION((short)2, "totalEdgesAfterOperation");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // TOTAL_VERTICES_AFTER_OPERATION
+          return TOTAL_VERTICES_AFTER_OPERATION;
+        case 2: // TOTAL_EDGES_AFTER_OPERATION
+          return TOTAL_EDGES_AFTER_OPERATION;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  private static final int __TOTALVERTICESAFTEROPERATION_ISSET_ID = 0;
+  private static final int __TOTALEDGESAFTEROPERATION_ISSET_ID = 1;
+  private byte __isset_bitfield = 0;
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.TOTAL_VERTICES_AFTER_OPERATION, new org.apache.thrift.meta_data.FieldMetaData("totalVerticesAfterOperation", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
+    tmpMap.put(_Fields.TOTAL_EDGES_AFTER_OPERATION, new org.apache.thrift.meta_data.FieldMetaData("totalEdgesAfterOperation", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AddGraphResponse.class, metaDataMap);
+  }
+
+  public AddGraphResponse() {
+  }
+
+  public AddGraphResponse(
+    long totalVerticesAfterOperation,
+    long totalEdgesAfterOperation)
+  {
+    this();
+    this.totalVerticesAfterOperation = totalVerticesAfterOperation;
+    setTotalVerticesAfterOperationIsSet(true);
+    this.totalEdgesAfterOperation = totalEdgesAfterOperation;
+    setTotalEdgesAfterOperationIsSet(true);
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public AddGraphResponse(AddGraphResponse other) {
+    __isset_bitfield = other.__isset_bitfield;
+    this.totalVerticesAfterOperation = other.totalVerticesAfterOperation;
+    this.totalEdgesAfterOperation = other.totalEdgesAfterOperation;
+  }
+
+  public AddGraphResponse deepCopy() {
+    return new AddGraphResponse(this);
+  }
+
+  @Override
+  public void clear() {
+    setTotalVerticesAfterOperationIsSet(false);
+    this.totalVerticesAfterOperation = 0;
+    setTotalEdgesAfterOperationIsSet(false);
+    this.totalEdgesAfterOperation = 0;
+  }
+
+  public long getTotalVerticesAfterOperation() {
+    return this.totalVerticesAfterOperation;
+  }
+
+  public AddGraphResponse setTotalVerticesAfterOperation(long totalVerticesAfterOperation) {
+    this.totalVerticesAfterOperation = totalVerticesAfterOperation;
+    setTotalVerticesAfterOperationIsSet(true);
+    return this;
+  }
+
+  public void unsetTotalVerticesAfterOperation() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __TOTALVERTICESAFTEROPERATION_ISSET_ID);
+  }
+
+  /** Returns true if field totalVerticesAfterOperation is set (has been assigned a value) and false otherwise */
+  public boolean isSetTotalVerticesAfterOperation() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __TOTALVERTICESAFTEROPERATION_ISSET_ID);
+  }
+
+  public void setTotalVerticesAfterOperationIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __TOTALVERTICESAFTEROPERATION_ISSET_ID, value);
+  }
+
+  public long getTotalEdgesAfterOperation() {
+    return this.totalEdgesAfterOperation;
+  }
+
+  public AddGraphResponse setTotalEdgesAfterOperation(long totalEdgesAfterOperation) {
+    this.totalEdgesAfterOperation = totalEdgesAfterOperation;
+    setTotalEdgesAfterOperationIsSet(true);
+    return this;
+  }
+
+  public void unsetTotalEdgesAfterOperation() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __TOTALEDGESAFTEROPERATION_ISSET_ID);
+  }
+
+  /** Returns true if field totalEdgesAfterOperation is set (has been assigned a value) and false otherwise */
+  public boolean isSetTotalEdgesAfterOperation() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __TOTALEDGESAFTEROPERATION_ISSET_ID);
+  }
+
+  public void setTotalEdgesAfterOperationIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __TOTALEDGESAFTEROPERATION_ISSET_ID, value);
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case TOTAL_VERTICES_AFTER_OPERATION:
+      if (value == null) {
+        unsetTotalVerticesAfterOperation();
+      } else {
+        setTotalVerticesAfterOperation((java.lang.Long)value);
+      }
+      break;
+
+    case TOTAL_EDGES_AFTER_OPERATION:
+      if (value == null) {
+        unsetTotalEdgesAfterOperation();
+      } else {
+        setTotalEdgesAfterOperation((java.lang.Long)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case TOTAL_VERTICES_AFTER_OPERATION:
+      return getTotalVerticesAfterOperation();
+
+    case TOTAL_EDGES_AFTER_OPERATION:
+      return getTotalEdgesAfterOperation();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case TOTAL_VERTICES_AFTER_OPERATION:
+      return isSetTotalVerticesAfterOperation();
+    case TOTAL_EDGES_AFTER_OPERATION:
+      return isSetTotalEdgesAfterOperation();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof AddGraphResponse)
+      return this.equals((AddGraphResponse)that);
+    return false;
+  }
+
+  public boolean equals(AddGraphResponse that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_totalVerticesAfterOperation = true;
+    boolean that_present_totalVerticesAfterOperation = true;
+    if (this_present_totalVerticesAfterOperation || that_present_totalVerticesAfterOperation) {
+      if (!(this_present_totalVerticesAfterOperation && that_present_totalVerticesAfterOperation))
+        return false;
+      if (this.totalVerticesAfterOperation != that.totalVerticesAfterOperation)
+        return false;
+    }
+
+    boolean this_present_totalEdgesAfterOperation = true;
+    boolean that_present_totalEdgesAfterOperation = true;
+    if (this_present_totalEdgesAfterOperation || that_present_totalEdgesAfterOperation) {
+      if (!(this_present_totalEdgesAfterOperation && that_present_totalEdgesAfterOperation))
+        return false;
+      if (this.totalEdgesAfterOperation != that.totalEdgesAfterOperation)
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(totalVerticesAfterOperation);
+
+    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(totalEdgesAfterOperation);
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(AddGraphResponse other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetTotalVerticesAfterOperation(), other.isSetTotalVerticesAfterOperation());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetTotalVerticesAfterOperation()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.totalVerticesAfterOperation, other.totalVerticesAfterOperation);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetTotalEdgesAfterOperation(), other.isSetTotalEdgesAfterOperation());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetTotalEdgesAfterOperation()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.totalEdgesAfterOperation, other.totalEdgesAfterOperation);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("AddGraphResponse(");
+    boolean first = true;
+
+    sb.append("totalVerticesAfterOperation:");
+    sb.append(this.totalVerticesAfterOperation);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("totalEdgesAfterOperation:");
+    sb.append(this.totalEdgesAfterOperation);
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
+      __isset_bitfield = 0;
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class AddGraphResponseStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AddGraphResponseStandardScheme getScheme() {
+      return new AddGraphResponseStandardScheme();
+    }
+  }
+
+  private static class AddGraphResponseStandardScheme extends org.apache.thrift.scheme.StandardScheme<AddGraphResponse> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, AddGraphResponse struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // TOTAL_VERTICES_AFTER_OPERATION
+            if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+              struct.totalVerticesAfterOperation = iprot.readI64();
+              struct.setTotalVerticesAfterOperationIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // TOTAL_EDGES_AFTER_OPERATION
+            if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+              struct.totalEdgesAfterOperation = iprot.readI64();
+              struct.setTotalEdgesAfterOperationIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, AddGraphResponse struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      oprot.writeFieldBegin(TOTAL_VERTICES_AFTER_OPERATION_FIELD_DESC);
+      oprot.writeI64(struct.totalVerticesAfterOperation);
+      oprot.writeFieldEnd();
+      oprot.writeFieldBegin(TOTAL_EDGES_AFTER_OPERATION_FIELD_DESC);
+      oprot.writeI64(struct.totalEdgesAfterOperation);
+      oprot.writeFieldEnd();
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class AddGraphResponseTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AddGraphResponseTupleScheme getScheme() {
+      return new AddGraphResponseTupleScheme();
+    }
+  }
+
+  private static class AddGraphResponseTupleScheme extends org.apache.thrift.scheme.TupleScheme<AddGraphResponse> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, AddGraphResponse struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetTotalVerticesAfterOperation()) {
+        optionals.set(0);
+      }
+      if (struct.isSetTotalEdgesAfterOperation()) {
+        optionals.set(1);
+      }
+      oprot.writeBitSet(optionals, 2);
+      if (struct.isSetTotalVerticesAfterOperation()) {
+        oprot.writeI64(struct.totalVerticesAfterOperation);
+      }
+      if (struct.isSetTotalEdgesAfterOperation()) {
+        oprot.writeI64(struct.totalEdgesAfterOperation);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, AddGraphResponse struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet incoming = iprot.readBitSet(2);
+      if (incoming.get(0)) {
+        struct.totalVerticesAfterOperation = iprot.readI64();
+        struct.setTotalVerticesAfterOperationIsSet(true);
+      }
+      if (incoming.get(1)) {
+        struct.totalEdgesAfterOperation = iprot.readI64();
+        struct.setTotalEdgesAfterOperationIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleService.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleService.java
new file mode 100644
index 0000000..da9d745
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleService.java
@@ -0,0 +1,1098 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class ExampleService {
+
+  public interface Iface {
+
+    public AddGraphResponse addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph) throws AddGraphException, org.apache.thrift.TException;
+
+  }
+
+  public interface AsyncIface {
+
+    public void addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph, org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse> resultHandler) throws org.apache.thrift.TException;
+
+  }
+
+  public static class Client extends org.apache.thrift.TServiceClient implements Iface {
+    public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
+      public Factory() {}
+      public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
+        return new Client(prot);
+      }
+      public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
+        return new Client(iprot, oprot);
+      }
+    }
+
+    public Client(org.apache.thrift.protocol.TProtocol prot)
+    {
+      super(prot, prot);
+    }
+
+    public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
+      super(iprot, oprot);
+    }
+
+    public AddGraphResponse addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph) throws AddGraphException, org.apache.thrift.TException
+    {
+      send_addGraph(graph);
+      return recv_addGraph();
+    }
+
+    public void send_addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph) throws org.apache.thrift.TException
+    {
+      addGraph_args args = new addGraph_args();
+      args.setGraph(graph);
+      sendBase("addGraph", args);
+    }
+
+    public AddGraphResponse recv_addGraph() throws AddGraphException, org.apache.thrift.TException
+    {
+      addGraph_result result = new addGraph_result();
+      receiveBase(result, "addGraph");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.error != null) {
+        throw result.error;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "addGraph failed: unknown result");
+    }
+
+  }
+  public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {
+    public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
+      private org.apache.thrift.async.TAsyncClientManager clientManager;
+      private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
+      public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
+        this.clientManager = clientManager;
+        this.protocolFactory = protocolFactory;
+      }
+      public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
+        return new AsyncClient(protocolFactory, clientManager, transport);
+      }
+    }
+
+    public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {
+      super(protocolFactory, clientManager, transport);
+    }
+
+    public void addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph, org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      addGraph_call method_call = new addGraph_call(graph, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class addGraph_call extends org.apache.thrift.async.TAsyncMethodCall<AddGraphResponse> {
+      private org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph;
+      public addGraph_call(org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph, org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.graph = graph;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("addGraph", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        addGraph_args args = new addGraph_args();
+        args.setGraph(graph);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public AddGraphResponse getResult() throws AddGraphException, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_addGraph();
+      }
+    }
+
+  }
+
+  public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
+    private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName());
+    public Processor(I iface) {
+      super(iface, getProcessMap(new java.util.HashMap<java.lang.String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
+    }
+
+    protected Processor(I iface, java.util.Map<java.lang.String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> processMap) {
+      super(iface, getProcessMap(processMap));
+    }
+
+    private static <I extends Iface> java.util.Map<java.lang.String,  org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> getProcessMap(java.util.Map<java.lang.String, org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
+      processMap.put("addGraph", new addGraph());
+      return processMap;
+    }
+
+    public static class addGraph<I extends Iface> extends org.apache.thrift.ProcessFunction<I, addGraph_args> {
+      public addGraph() {
+        super("addGraph");
+      }
+
+      public addGraph_args getEmptyArgsInstance() {
+        return new addGraph_args();
+      }
+
+      protected boolean isOneway() {
+        return false;
+      }
+
+      @Override
+      protected boolean rethrowUnhandledExceptions() {
+        return false;
+      }
+
+      public addGraph_result getResult(I iface, addGraph_args args) throws org.apache.thrift.TException {
+        addGraph_result result = new addGraph_result();
+        try {
+          result.success = iface.addGraph(args.graph);
+        } catch (AddGraphException error) {
+          result.error = error;
+        }
+        return result;
+      }
+    }
+
+  }
+
+  public static class AsyncProcessor<I extends AsyncIface> extends org.apache.thrift.TBaseAsyncProcessor<I> {
+    private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName());
+    public AsyncProcessor(I iface) {
+      super(iface, getProcessMap(new java.util.HashMap<java.lang.String, org.apache.thrift.AsyncProcessFunction<I, ? extends org.apache.thrift.TBase, ?>>()));
+    }
+
+    protected AsyncProcessor(I iface, java.util.Map<java.lang.String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {
+      super(iface, getProcessMap(processMap));
+    }
+
+    private static <I extends AsyncIface> java.util.Map<java.lang.String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase,?>> getProcessMap(java.util.Map<java.lang.String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {
+      processMap.put("addGraph", new addGraph());
+      return processMap;
+    }
+
+    public static class addGraph<I extends AsyncIface> extends org.apache.thrift.AsyncProcessFunction<I, addGraph_args, AddGraphResponse> {
+      public addGraph() {
+        super("addGraph");
+      }
+
+      public addGraph_args getEmptyArgsInstance() {
+        return new addGraph_args();
+      }
+
+      public org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse> getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) {
+        final org.apache.thrift.AsyncProcessFunction fcall = this;
+        return new org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse>() { 
+          public void onComplete(AddGraphResponse o) {
+            addGraph_result result = new addGraph_result();
+            result.success = o;
+            try {
+              fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);
+            } catch (org.apache.thrift.transport.TTransportException e) {
+              _LOGGER.error("TTransportException writing to internal frame buffer", e);
+              fb.close();
+            } catch (java.lang.Exception e) {
+              _LOGGER.error("Exception writing to internal frame buffer", e);
+              onError(e);
+            }
+          }
+          public void onError(java.lang.Exception e) {
+            byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;
+            org.apache.thrift.TSerializable msg;
+            addGraph_result result = new addGraph_result();
+            if (e instanceof AddGraphException) {
+              result.error = (AddGraphException) e;
+              result.setErrorIsSet(true);
+              msg = result;
+            } else if (e instanceof org.apache.thrift.transport.TTransportException) {
+              _LOGGER.error("TTransportException inside handler", e);
+              fb.close();
+              return;
+            } else if (e instanceof org.apache.thrift.TApplicationException) {
+              _LOGGER.error("TApplicationException inside handler", e);
+              msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
+              msg = (org.apache.thrift.TApplicationException)e;
+            } else {
+              _LOGGER.error("Exception inside handler", e);
+              msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
+              msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage());
+            }
+            try {
+              fcall.sendResponse(fb,msg,msgType,seqid);
+            } catch (java.lang.Exception ex) {
+              _LOGGER.error("Exception writing to internal frame buffer", ex);
+              fb.close();
+            }
+          }
+        };
+      }
+
+      protected boolean isOneway() {
+        return false;
+      }
+
+      public void start(I iface, addGraph_args args, org.apache.thrift.async.AsyncMethodCallback<AddGraphResponse> resultHandler) throws org.apache.thrift.TException {
+        iface.addGraph(args.graph,resultHandler);
+      }
+    }
+
+  }
+
+  public static class addGraph_args implements org.apache.thrift.TBase<addGraph_args, addGraph_args._Fields>, java.io.Serializable, Cloneable, Comparable<addGraph_args>   {
+    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("addGraph_args");
+
+    private static final org.apache.thrift.protocol.TField GRAPH_FIELD_DESC = new org.apache.thrift.protocol.TField("graph", org.apache.thrift.protocol.TType.STRUCT, (short)1);
+
+    private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new addGraph_argsStandardSchemeFactory();
+    private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new addGraph_argsTupleSchemeFactory();
+
+    public @org.apache.thrift.annotation.Nullable org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph; // required
+
+    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+      GRAPH((short)1, "graph");
+
+      private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+      static {
+        for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+          byName.put(field.getFieldName(), field);
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByThriftId(int fieldId) {
+        switch(fieldId) {
+          case 1: // GRAPH
+            return GRAPH;
+          default:
+            return null;
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, throwing an exception
+       * if it is not found.
+       */
+      public static _Fields findByThriftIdOrThrow(int fieldId) {
+        _Fields fields = findByThriftId(fieldId);
+        if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+        return fields;
+      }
+
+      /**
+       * Find the _Fields constant that matches name, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByName(java.lang.String name) {
+        return byName.get(name);
+      }
+
+      private final short _thriftId;
+      private final java.lang.String _fieldName;
+
+      _Fields(short thriftId, java.lang.String fieldName) {
+        _thriftId = thriftId;
+        _fieldName = fieldName;
+      }
+
+      public short getThriftFieldId() {
+        return _thriftId;
+      }
+
+      public java.lang.String getFieldName() {
+        return _fieldName;
+      }
+    }
+
+    // isset id assignments
+    public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+    static {
+      java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+      tmpMap.put(_Fields.GRAPH, new org.apache.thrift.meta_data.FieldMetaData("graph", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, org.apache.tinkerpop.gremlin.language.property_graphs.Graph.class)));
+      metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+      org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(addGraph_args.class, metaDataMap);
+    }
+
+    public addGraph_args() {
+    }
+
+    public addGraph_args(
+      org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph)
+    {
+      this();
+      this.graph = graph;
+    }
+
+    /**
+     * Performs a deep copy on <i>other</i>.
+     */
+    public addGraph_args(addGraph_args other) {
+      if (other.isSetGraph()) {
+        this.graph = new org.apache.tinkerpop.gremlin.language.property_graphs.Graph(other.graph);
+      }
+    }
+
+    public addGraph_args deepCopy() {
+      return new addGraph_args(this);
+    }
+
+    @Override
+    public void clear() {
+      this.graph = null;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public org.apache.tinkerpop.gremlin.language.property_graphs.Graph getGraph() {
+      return this.graph;
+    }
+
+    public addGraph_args setGraph(@org.apache.thrift.annotation.Nullable org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph) {
+      this.graph = graph;
+      return this;
+    }
+
+    public void unsetGraph() {
+      this.graph = null;
+    }
+
+    /** Returns true if field graph is set (has been assigned a value) and false otherwise */
+    public boolean isSetGraph() {
+      return this.graph != null;
+    }
+
+    public void setGraphIsSet(boolean value) {
+      if (!value) {
+        this.graph = null;
+      }
+    }
+
+    public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+      switch (field) {
+      case GRAPH:
+        if (value == null) {
+          unsetGraph();
+        } else {
+          setGraph((org.apache.tinkerpop.gremlin.language.property_graphs.Graph)value);
+        }
+        break;
+
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public java.lang.Object getFieldValue(_Fields field) {
+      switch (field) {
+      case GRAPH:
+        return getGraph();
+
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+    public boolean isSet(_Fields field) {
+      if (field == null) {
+        throw new java.lang.IllegalArgumentException();
+      }
+
+      switch (field) {
+      case GRAPH:
+        return isSetGraph();
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    @Override
+    public boolean equals(java.lang.Object that) {
+      if (that instanceof addGraph_args)
+        return this.equals((addGraph_args)that);
+      return false;
+    }
+
+    public boolean equals(addGraph_args that) {
+      if (that == null)
+        return false;
+      if (this == that)
+        return true;
+
+      boolean this_present_graph = true && this.isSetGraph();
+      boolean that_present_graph = true && that.isSetGraph();
+      if (this_present_graph || that_present_graph) {
+        if (!(this_present_graph && that_present_graph))
+          return false;
+        if (!this.graph.equals(that.graph))
+          return false;
+      }
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int hashCode = 1;
+
+      hashCode = hashCode * 8191 + ((isSetGraph()) ? 131071 : 524287);
+      if (isSetGraph())
+        hashCode = hashCode * 8191 + graph.hashCode();
+
+      return hashCode;
+    }
+
+    @Override
+    public int compareTo(addGraph_args other) {
+      if (!getClass().equals(other.getClass())) {
+        return getClass().getName().compareTo(other.getClass().getName());
+      }
+
+      int lastComparison = 0;
+
+      lastComparison = java.lang.Boolean.compare(isSetGraph(), other.isSetGraph());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetGraph()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.graph, other.graph);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      return 0;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public _Fields fieldForId(int fieldId) {
+      return _Fields.findByThriftId(fieldId);
+    }
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+      scheme(iprot).read(iprot, this);
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+      scheme(oprot).write(oprot, this);
+    }
+
+    @Override
+    public java.lang.String toString() {
+      java.lang.StringBuilder sb = new java.lang.StringBuilder("addGraph_args(");
+      boolean first = true;
+
+      sb.append("graph:");
+      if (this.graph == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.graph);
+      }
+      first = false;
+      sb.append(")");
+      return sb.toString();
+    }
+
+    public void validate() throws org.apache.thrift.TException {
+      // check for required fields
+      // check for sub-struct validity
+      if (graph != null) {
+        graph.validate();
+      }
+    }
+
+    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+      try {
+        write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+      try {
+        read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private static class addGraph_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+      public addGraph_argsStandardScheme getScheme() {
+        return new addGraph_argsStandardScheme();
+      }
+    }
+
+    private static class addGraph_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme<addGraph_args> {
+
+      public void read(org.apache.thrift.protocol.TProtocol iprot, addGraph_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TField schemeField;
+        iprot.readStructBegin();
+        while (true)
+        {
+          schemeField = iprot.readFieldBegin();
+          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+            break;
+          }
+          switch (schemeField.id) {
+            case 1: // GRAPH
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+                struct.graph = new org.apache.tinkerpop.gremlin.language.property_graphs.Graph();
+                struct.graph.read(iprot);
+                struct.setGraphIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
+            default:
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+          }
+          iprot.readFieldEnd();
+        }
+        iprot.readStructEnd();
+
+        // check for required fields of primitive type, which can't be checked in the validate method
+        struct.validate();
+      }
+
+      public void write(org.apache.thrift.protocol.TProtocol oprot, addGraph_args struct) throws org.apache.thrift.TException {
+        struct.validate();
+
+        oprot.writeStructBegin(STRUCT_DESC);
+        if (struct.graph != null) {
+          oprot.writeFieldBegin(GRAPH_FIELD_DESC);
+          struct.graph.write(oprot);
+          oprot.writeFieldEnd();
+        }
+        oprot.writeFieldStop();
+        oprot.writeStructEnd();
+      }
+
+    }
+
+    private static class addGraph_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+      public addGraph_argsTupleScheme getScheme() {
+        return new addGraph_argsTupleScheme();
+      }
+    }
+
+    private static class addGraph_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme<addGraph_args> {
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol prot, addGraph_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet optionals = new java.util.BitSet();
+        if (struct.isSetGraph()) {
+          optionals.set(0);
+        }
+        oprot.writeBitSet(optionals, 1);
+        if (struct.isSetGraph()) {
+          struct.graph.write(oprot);
+        }
+      }
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol prot, addGraph_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet incoming = iprot.readBitSet(1);
+        if (incoming.get(0)) {
+          struct.graph = new org.apache.tinkerpop.gremlin.language.property_graphs.Graph();
+          struct.graph.read(iprot);
+          struct.setGraphIsSet(true);
+        }
+      }
+    }
+
+    private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+      return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+    }
+  }
+
+  public static class addGraph_result implements org.apache.thrift.TBase<addGraph_result, addGraph_result._Fields>, java.io.Serializable, Cloneable, Comparable<addGraph_result>   {
+    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("addGraph_result");
+
+    private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRUCT, (short)0);
+    private static final org.apache.thrift.protocol.TField ERROR_FIELD_DESC = new org.apache.thrift.protocol.TField("error", org.apache.thrift.protocol.TType.STRUCT, (short)1);
+
+    private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new addGraph_resultStandardSchemeFactory();
+    private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new addGraph_resultTupleSchemeFactory();
+
+    public @org.apache.thrift.annotation.Nullable AddGraphResponse success; // required
+    public @org.apache.thrift.annotation.Nullable AddGraphException error; // required
+
+    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+      SUCCESS((short)0, "success"),
+      ERROR((short)1, "error");
+
+      private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+      static {
+        for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+          byName.put(field.getFieldName(), field);
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByThriftId(int fieldId) {
+        switch(fieldId) {
+          case 0: // SUCCESS
+            return SUCCESS;
+          case 1: // ERROR
+            return ERROR;
+          default:
+            return null;
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, throwing an exception
+       * if it is not found.
+       */
+      public static _Fields findByThriftIdOrThrow(int fieldId) {
+        _Fields fields = findByThriftId(fieldId);
+        if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+        return fields;
+      }
+
+      /**
+       * Find the _Fields constant that matches name, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByName(java.lang.String name) {
+        return byName.get(name);
+      }
+
+      private final short _thriftId;
+      private final java.lang.String _fieldName;
+
+      _Fields(short thriftId, java.lang.String fieldName) {
+        _thriftId = thriftId;
+        _fieldName = fieldName;
+      }
+
+      public short getThriftFieldId() {
+        return _thriftId;
+      }
+
+      public java.lang.String getFieldName() {
+        return _fieldName;
+      }
+    }
+
+    // isset id assignments
+    public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+    static {
+      java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+      tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, AddGraphResponse.class)));
+      tmpMap.put(_Fields.ERROR, new org.apache.thrift.meta_data.FieldMetaData("error", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, AddGraphException.class)));
+      metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+      org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(addGraph_result.class, metaDataMap);
+    }
+
+    public addGraph_result() {
+    }
+
+    public addGraph_result(
+      AddGraphResponse success,
+      AddGraphException error)
+    {
+      this();
+      this.success = success;
+      this.error = error;
+    }
+
+    /**
+     * Performs a deep copy on <i>other</i>.
+     */
+    public addGraph_result(addGraph_result other) {
+      if (other.isSetSuccess()) {
+        this.success = new AddGraphResponse(other.success);
+      }
+      if (other.isSetError()) {
+        this.error = new AddGraphException(other.error);
+      }
+    }
+
+    public addGraph_result deepCopy() {
+      return new addGraph_result(this);
+    }
+
+    @Override
+    public void clear() {
+      this.success = null;
+      this.error = null;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public AddGraphResponse getSuccess() {
+      return this.success;
+    }
+
+    public addGraph_result setSuccess(@org.apache.thrift.annotation.Nullable AddGraphResponse success) {
+      this.success = success;
+      return this;
+    }
+
+    public void unsetSuccess() {
+      this.success = null;
+    }
+
+    /** Returns true if field success is set (has been assigned a value) and false otherwise */
+    public boolean isSetSuccess() {
+      return this.success != null;
+    }
+
+    public void setSuccessIsSet(boolean value) {
+      if (!value) {
+        this.success = null;
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public AddGraphException getError() {
+      return this.error;
+    }
+
+    public addGraph_result setError(@org.apache.thrift.annotation.Nullable AddGraphException error) {
+      this.error = error;
+      return this;
+    }
+
+    public void unsetError() {
+      this.error = null;
+    }
+
+    /** Returns true if field error is set (has been assigned a value) and false otherwise */
+    public boolean isSetError() {
+      return this.error != null;
+    }
+
+    public void setErrorIsSet(boolean value) {
+      if (!value) {
+        this.error = null;
+      }
+    }
+
+    public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+      switch (field) {
+      case SUCCESS:
+        if (value == null) {
+          unsetSuccess();
+        } else {
+          setSuccess((AddGraphResponse)value);
+        }
+        break;
+
+      case ERROR:
+        if (value == null) {
+          unsetError();
+        } else {
+          setError((AddGraphException)value);
+        }
+        break;
+
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public java.lang.Object getFieldValue(_Fields field) {
+      switch (field) {
+      case SUCCESS:
+        return getSuccess();
+
+      case ERROR:
+        return getError();
+
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+    public boolean isSet(_Fields field) {
+      if (field == null) {
+        throw new java.lang.IllegalArgumentException();
+      }
+
+      switch (field) {
+      case SUCCESS:
+        return isSetSuccess();
+      case ERROR:
+        return isSetError();
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    @Override
+    public boolean equals(java.lang.Object that) {
+      if (that instanceof addGraph_result)
+        return this.equals((addGraph_result)that);
+      return false;
+    }
+
+    public boolean equals(addGraph_result that) {
+      if (that == null)
+        return false;
+      if (this == that)
+        return true;
+
+      boolean this_present_success = true && this.isSetSuccess();
+      boolean that_present_success = true && that.isSetSuccess();
+      if (this_present_success || that_present_success) {
+        if (!(this_present_success && that_present_success))
+          return false;
+        if (!this.success.equals(that.success))
+          return false;
+      }
+
+      boolean this_present_error = true && this.isSetError();
+      boolean that_present_error = true && that.isSetError();
+      if (this_present_error || that_present_error) {
+        if (!(this_present_error && that_present_error))
+          return false;
+        if (!this.error.equals(that.error))
+          return false;
+      }
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int hashCode = 1;
+
+      hashCode = hashCode * 8191 + ((isSetSuccess()) ? 131071 : 524287);
+      if (isSetSuccess())
+        hashCode = hashCode * 8191 + success.hashCode();
+
+      hashCode = hashCode * 8191 + ((isSetError()) ? 131071 : 524287);
+      if (isSetError())
+        hashCode = hashCode * 8191 + error.hashCode();
+
+      return hashCode;
+    }
+
+    @Override
+    public int compareTo(addGraph_result other) {
+      if (!getClass().equals(other.getClass())) {
+        return getClass().getName().compareTo(other.getClass().getName());
+      }
+
+      int lastComparison = 0;
+
+      lastComparison = java.lang.Boolean.compare(isSetSuccess(), other.isSetSuccess());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetSuccess()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      lastComparison = java.lang.Boolean.compare(isSetError(), other.isSetError());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetError()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.error, other.error);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      return 0;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public _Fields fieldForId(int fieldId) {
+      return _Fields.findByThriftId(fieldId);
+    }
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+      scheme(iprot).read(iprot, this);
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+      scheme(oprot).write(oprot, this);
+      }
+
+    @Override
+    public java.lang.String toString() {
+      java.lang.StringBuilder sb = new java.lang.StringBuilder("addGraph_result(");
+      boolean first = true;
+
+      sb.append("success:");
+      if (this.success == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.success);
+      }
+      first = false;
+      if (!first) sb.append(", ");
+      sb.append("error:");
+      if (this.error == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.error);
+      }
+      first = false;
+      sb.append(")");
+      return sb.toString();
+    }
+
+    public void validate() throws org.apache.thrift.TException {
+      // check for required fields
+      // check for sub-struct validity
+      if (success != null) {
+        success.validate();
+      }
+    }
+
+    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+      try {
+        write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+      try {
+        read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private static class addGraph_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+      public addGraph_resultStandardScheme getScheme() {
+        return new addGraph_resultStandardScheme();
+      }
+    }
+
+    private static class addGraph_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme<addGraph_result> {
+
+      public void read(org.apache.thrift.protocol.TProtocol iprot, addGraph_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TField schemeField;
+        iprot.readStructBegin();
+        while (true)
+        {
+          schemeField = iprot.readFieldBegin();
+          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+            break;
+          }
+          switch (schemeField.id) {
+            case 0: // SUCCESS
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+                struct.success = new AddGraphResponse();
+                struct.success.read(iprot);
+                struct.setSuccessIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
+            case 1: // ERROR
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+                struct.error = new AddGraphException();
+                struct.error.read(iprot);
+                struct.setErrorIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
+            default:
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+          }
+          iprot.readFieldEnd();
+        }
+        iprot.readStructEnd();
+
+        // check for required fields of primitive type, which can't be checked in the validate method
+        struct.validate();
+      }
+
+      public void write(org.apache.thrift.protocol.TProtocol oprot, addGraph_result struct) throws org.apache.thrift.TException {
+        struct.validate();
+
+        oprot.writeStructBegin(STRUCT_DESC);
+        if (struct.success != null) {
+          oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
+          struct.success.write(oprot);
+          oprot.writeFieldEnd();
+        }
+        if (struct.error != null) {
+          oprot.writeFieldBegin(ERROR_FIELD_DESC);
+          struct.error.write(oprot);
+          oprot.writeFieldEnd();
+        }
+        oprot.writeFieldStop();
+        oprot.writeStructEnd();
+      }
+
+    }
+
+    private static class addGraph_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+      public addGraph_resultTupleScheme getScheme() {
+        return new addGraph_resultTupleScheme();
+      }
+    }
+
+    private static class addGraph_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme<addGraph_result> {
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol prot, addGraph_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet optionals = new java.util.BitSet();
+        if (struct.isSetSuccess()) {
+          optionals.set(0);
+        }
+        if (struct.isSetError()) {
+          optionals.set(1);
+        }
+        oprot.writeBitSet(optionals, 2);
+        if (struct.isSetSuccess()) {
+          struct.success.write(oprot);
+        }
+        if (struct.isSetError()) {
+          struct.error.write(oprot);
+        }
+      }
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol prot, addGraph_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet incoming = iprot.readBitSet(2);
+        if (incoming.get(0)) {
+          struct.success = new AddGraphResponse();
+          struct.success.read(iprot);
+          struct.setSuccessIsSet(true);
+        }
+        if (incoming.get(1)) {
+          struct.error = new AddGraphException();
+          struct.error.read(iprot);
+          struct.setErrorIsSet(true);
+        }
+      }
+    }
+
+    private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+      return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+    }
+  }
+
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/AtomicValue.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/AtomicValue.java
new file mode 100644
index 0000000..d8ce6be
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/AtomicValue.java
@@ -0,0 +1,757 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A simple value like a boolean, number, or string
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class AtomicValue extends org.apache.thrift.TUnion<AtomicValue, AtomicValue._Fields> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AtomicValue");
+  private static final org.apache.thrift.protocol.TField BOOLEAN_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("booleanEsc", org.apache.thrift.protocol.TType.BOOL, (short)1);
+  private static final org.apache.thrift.protocol.TField BYTE_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("byteEsc", org.apache.thrift.protocol.TType.I16, (short)2);
+  private static final org.apache.thrift.protocol.TField DOUBLE_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("doubleEsc", org.apache.thrift.protocol.TType.DOUBLE, (short)3);
+  private static final org.apache.thrift.protocol.TField FLOAT_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("floatEsc", org.apache.thrift.protocol.TType.DOUBLE, (short)4);
+  private static final org.apache.thrift.protocol.TField INTEGER_FIELD_DESC = new org.apache.thrift.protocol.TField("integer", org.apache.thrift.protocol.TType.I32, (short)5);
+  private static final org.apache.thrift.protocol.TField LONG_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("longEsc", org.apache.thrift.protocol.TType.I64, (short)6);
+  private static final org.apache.thrift.protocol.TField STRING_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("stringEsc", org.apache.thrift.protocol.TType.STRING, (short)7);
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * A boolean (true/false) value
+     * 
+     * @type boolean
+     */
+    BOOLEAN_ESC((short)1, "booleanEsc"),
+    /**
+     * A byte (8-bit integer) value
+     * 
+     * @type integer:
+     *         precision:
+     *           bits: 8
+     */
+    BYTE_ESC((short)2, "byteEsc"),
+    /**
+     * A double-precision (64-bit) floating point value
+     * 
+     * @type float:
+     *         precision:
+     *           bits: 64
+     */
+    DOUBLE_ESC((short)3, "doubleEsc"),
+    /**
+     * A single-precision (32-bit) floating point value
+     * 
+     * @type float
+     */
+    FLOAT_ESC((short)4, "floatEsc"),
+    /**
+     * A 32-bit integer value
+     * 
+     * @type integer
+     */
+    INTEGER((short)5, "integer"),
+    /**
+     * A 64-bit integer value
+     * 
+     * @type integer:
+     *         precision:
+     *           bits: 64
+     */
+    LONG_ESC((short)6, "longEsc"),
+    /**
+     * A string value
+     * 
+     * @type string
+     */
+    STRING_ESC((short)7, "stringEsc");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // BOOLEAN_ESC
+          return BOOLEAN_ESC;
+        case 2: // BYTE_ESC
+          return BYTE_ESC;
+        case 3: // DOUBLE_ESC
+          return DOUBLE_ESC;
+        case 4: // FLOAT_ESC
+          return FLOAT_ESC;
+        case 5: // INTEGER
+          return INTEGER;
+        case 6: // LONG_ESC
+          return LONG_ESC;
+        case 7: // STRING_ESC
+          return STRING_ESC;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.BOOLEAN_ESC, new org.apache.thrift.meta_data.FieldMetaData("booleanEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL)));
+    tmpMap.put(_Fields.BYTE_ESC, new org.apache.thrift.meta_data.FieldMetaData("byteEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I16)));
+    tmpMap.put(_Fields.DOUBLE_ESC, new org.apache.thrift.meta_data.FieldMetaData("doubleEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.DOUBLE)));
+    tmpMap.put(_Fields.FLOAT_ESC, new org.apache.thrift.meta_data.FieldMetaData("floatEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.DOUBLE)));
+    tmpMap.put(_Fields.INTEGER, new org.apache.thrift.meta_data.FieldMetaData("integer", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.LONG_ESC, new org.apache.thrift.meta_data.FieldMetaData("longEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
+    tmpMap.put(_Fields.STRING_ESC, new org.apache.thrift.meta_data.FieldMetaData("stringEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AtomicValue.class, metaDataMap);
+  }
+
+  public AtomicValue() {
+    super();
+  }
+
+  public AtomicValue(_Fields setField, java.lang.Object value) {
+    super(setField, value);
+  }
+
+  public AtomicValue(AtomicValue other) {
+    super(other);
+  }
+  public AtomicValue deepCopy() {
+    return new AtomicValue(this);
+  }
+
+  public static AtomicValue booleanEsc(boolean value) {
+    AtomicValue x = new AtomicValue();
+    x.setBooleanEsc(value);
+    return x;
+  }
+
+  public static AtomicValue byteEsc(short value) {
+    AtomicValue x = new AtomicValue();
+    x.setByteEsc(value);
+    return x;
+  }
+
+  public static AtomicValue doubleEsc(double value) {
+    AtomicValue x = new AtomicValue();
+    x.setDoubleEsc(value);
+    return x;
+  }
+
+  public static AtomicValue floatEsc(double value) {
+    AtomicValue x = new AtomicValue();
+    x.setFloatEsc(value);
+    return x;
+  }
+
+  public static AtomicValue integer(int value) {
+    AtomicValue x = new AtomicValue();
+    x.setInteger(value);
+    return x;
+  }
+
+  public static AtomicValue longEsc(long value) {
+    AtomicValue x = new AtomicValue();
+    x.setLongEsc(value);
+    return x;
+  }
+
+  public static AtomicValue stringEsc(java.lang.String value) {
+    AtomicValue x = new AtomicValue();
+    x.setStringEsc(value);
+    return x;
+  }
+
+
+  @Override
+  protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException {
+    switch (setField) {
+      case BOOLEAN_ESC:
+        if (value instanceof java.lang.Boolean) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Boolean for field 'booleanEsc', but got " + value.getClass().getSimpleName());
+      case BYTE_ESC:
+        if (value instanceof java.lang.Short) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Short for field 'byteEsc', but got " + value.getClass().getSimpleName());
+      case DOUBLE_ESC:
+        if (value instanceof java.lang.Double) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Double for field 'doubleEsc', but got " + value.getClass().getSimpleName());
+      case FLOAT_ESC:
+        if (value instanceof java.lang.Double) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Double for field 'floatEsc', but got " + value.getClass().getSimpleName());
+      case INTEGER:
+        if (value instanceof java.lang.Integer) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Integer for field 'integer', but got " + value.getClass().getSimpleName());
+      case LONG_ESC:
+        if (value instanceof java.lang.Long) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.Long for field 'longEsc', but got " + value.getClass().getSimpleName());
+      case STRING_ESC:
+        if (value instanceof java.lang.String) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.String for field 'stringEsc', but got " + value.getClass().getSimpleName());
+      default:
+        throw new java.lang.IllegalArgumentException("Unknown field id " + setField);
+    }
+  }
+
+  @Override
+  protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TField field) throws org.apache.thrift.TException {
+    _Fields setField = _Fields.findByThriftId(field.id);
+    if (setField != null) {
+      switch (setField) {
+        case BOOLEAN_ESC:
+          if (field.type == BOOLEAN_ESC_FIELD_DESC.type) {
+            java.lang.Boolean booleanEsc;
+            booleanEsc = iprot.readBool();
+            return booleanEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case BYTE_ESC:
+          if (field.type == BYTE_ESC_FIELD_DESC.type) {
+            java.lang.Short byteEsc;
+            byteEsc = iprot.readI16();
+            return byteEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case DOUBLE_ESC:
+          if (field.type == DOUBLE_ESC_FIELD_DESC.type) {
+            java.lang.Double doubleEsc;
+            doubleEsc = iprot.readDouble();
+            return doubleEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case FLOAT_ESC:
+          if (field.type == FLOAT_ESC_FIELD_DESC.type) {
+            java.lang.Double floatEsc;
+            floatEsc = iprot.readDouble();
+            return floatEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case INTEGER:
+          if (field.type == INTEGER_FIELD_DESC.type) {
+            java.lang.Integer integer;
+            integer = iprot.readI32();
+            return integer;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case LONG_ESC:
+          if (field.type == LONG_ESC_FIELD_DESC.type) {
+            java.lang.Long longEsc;
+            longEsc = iprot.readI64();
+            return longEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case STRING_ESC:
+          if (field.type == STRING_ESC_FIELD_DESC.type) {
+            java.lang.String stringEsc;
+            stringEsc = iprot.readString();
+            return stringEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        default:
+          throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!");
+      }
+    } else {
+      org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+      return null;
+    }
+  }
+
+  @Override
+  protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    switch (setField_) {
+      case BOOLEAN_ESC:
+        java.lang.Boolean booleanEsc = (java.lang.Boolean)value_;
+        oprot.writeBool(booleanEsc);
+        return;
+      case BYTE_ESC:
+        java.lang.Short byteEsc = (java.lang.Short)value_;
+        oprot.writeI16(byteEsc);
+        return;
+      case DOUBLE_ESC:
+        java.lang.Double doubleEsc = (java.lang.Double)value_;
+        oprot.writeDouble(doubleEsc);
+        return;
+      case FLOAT_ESC:
+        java.lang.Double floatEsc = (java.lang.Double)value_;
+        oprot.writeDouble(floatEsc);
+        return;
+      case INTEGER:
+        java.lang.Integer integer = (java.lang.Integer)value_;
+        oprot.writeI32(integer);
+        return;
+      case LONG_ESC:
+        java.lang.Long longEsc = (java.lang.Long)value_;
+        oprot.writeI64(longEsc);
+        return;
+      case STRING_ESC:
+        java.lang.String stringEsc = (java.lang.String)value_;
+        oprot.writeString(stringEsc);
+        return;
+      default:
+        throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_);
+    }
+  }
+
+  @Override
+  protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, short fieldID) throws org.apache.thrift.TException {
+    _Fields setField = _Fields.findByThriftId(fieldID);
+    if (setField != null) {
+      switch (setField) {
+        case BOOLEAN_ESC:
+          java.lang.Boolean booleanEsc;
+          booleanEsc = iprot.readBool();
+          return booleanEsc;
+        case BYTE_ESC:
+          java.lang.Short byteEsc;
+          byteEsc = iprot.readI16();
+          return byteEsc;
+        case DOUBLE_ESC:
+          java.lang.Double doubleEsc;
+          doubleEsc = iprot.readDouble();
+          return doubleEsc;
+        case FLOAT_ESC:
+          java.lang.Double floatEsc;
+          floatEsc = iprot.readDouble();
+          return floatEsc;
+        case INTEGER:
+          java.lang.Integer integer;
+          integer = iprot.readI32();
+          return integer;
+        case LONG_ESC:
+          java.lang.Long longEsc;
+          longEsc = iprot.readI64();
+          return longEsc;
+        case STRING_ESC:
+          java.lang.String stringEsc;
+          stringEsc = iprot.readString();
+          return stringEsc;
+        default:
+          throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!");
+      }
+    } else {
+      throw new org.apache.thrift.protocol.TProtocolException("Couldn't find a field with field id " + fieldID);
+    }
+  }
+
+  @Override
+  protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    switch (setField_) {
+      case BOOLEAN_ESC:
+        java.lang.Boolean booleanEsc = (java.lang.Boolean)value_;
+        oprot.writeBool(booleanEsc);
+        return;
+      case BYTE_ESC:
+        java.lang.Short byteEsc = (java.lang.Short)value_;
+        oprot.writeI16(byteEsc);
+        return;
+      case DOUBLE_ESC:
+        java.lang.Double doubleEsc = (java.lang.Double)value_;
+        oprot.writeDouble(doubleEsc);
+        return;
+      case FLOAT_ESC:
+        java.lang.Double floatEsc = (java.lang.Double)value_;
+        oprot.writeDouble(floatEsc);
+        return;
+      case INTEGER:
+        java.lang.Integer integer = (java.lang.Integer)value_;
+        oprot.writeI32(integer);
+        return;
+      case LONG_ESC:
+        java.lang.Long longEsc = (java.lang.Long)value_;
+        oprot.writeI64(longEsc);
+        return;
+      case STRING_ESC:
+        java.lang.String stringEsc = (java.lang.String)value_;
+        oprot.writeString(stringEsc);
+        return;
+      default:
+        throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_);
+    }
+  }
+
+  @Override
+  protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {
+    switch (setField) {
+      case BOOLEAN_ESC:
+        return BOOLEAN_ESC_FIELD_DESC;
+      case BYTE_ESC:
+        return BYTE_ESC_FIELD_DESC;
+      case DOUBLE_ESC:
+        return DOUBLE_ESC_FIELD_DESC;
+      case FLOAT_ESC:
+        return FLOAT_ESC_FIELD_DESC;
+      case INTEGER:
+        return INTEGER_FIELD_DESC;
+      case LONG_ESC:
+        return LONG_ESC_FIELD_DESC;
+      case STRING_ESC:
+        return STRING_ESC_FIELD_DESC;
+      default:
+        throw new java.lang.IllegalArgumentException("Unknown field id " + setField);
+    }
+  }
+
+  @Override
+  protected org.apache.thrift.protocol.TStruct getStructDesc() {
+    return STRUCT_DESC;
+  }
+
+  @Override
+  protected _Fields enumForId(short id) {
+    return _Fields.findByThriftIdOrThrow(id);
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+
+  /**
+   * A boolean (true/false) value
+   * 
+   * @type boolean
+   */
+  public boolean getBooleanEsc() {
+    if (getSetField() == _Fields.BOOLEAN_ESC) {
+      return (java.lang.Boolean)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'booleanEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A boolean (true/false) value
+   * 
+   * @type boolean
+   */
+  public void setBooleanEsc(boolean value) {
+    setField_ = _Fields.BOOLEAN_ESC;
+    value_ = value;
+  }
+
+  /**
+   * A byte (8-bit integer) value
+   * 
+   * @type integer:
+   *         precision:
+   *           bits: 8
+   */
+  public short getByteEsc() {
+    if (getSetField() == _Fields.BYTE_ESC) {
+      return (java.lang.Short)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'byteEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A byte (8-bit integer) value
+   * 
+   * @type integer:
+   *         precision:
+   *           bits: 8
+   */
+  public void setByteEsc(short value) {
+    setField_ = _Fields.BYTE_ESC;
+    value_ = value;
+  }
+
+  /**
+   * A double-precision (64-bit) floating point value
+   * 
+   * @type float:
+   *         precision:
+   *           bits: 64
+   */
+  public double getDoubleEsc() {
+    if (getSetField() == _Fields.DOUBLE_ESC) {
+      return (java.lang.Double)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'doubleEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A double-precision (64-bit) floating point value
+   * 
+   * @type float:
+   *         precision:
+   *           bits: 64
+   */
+  public void setDoubleEsc(double value) {
+    setField_ = _Fields.DOUBLE_ESC;
+    value_ = value;
+  }
+
+  /**
+   * A single-precision (32-bit) floating point value
+   * 
+   * @type float
+   */
+  public double getFloatEsc() {
+    if (getSetField() == _Fields.FLOAT_ESC) {
+      return (java.lang.Double)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'floatEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A single-precision (32-bit) floating point value
+   * 
+   * @type float
+   */
+  public void setFloatEsc(double value) {
+    setField_ = _Fields.FLOAT_ESC;
+    value_ = value;
+  }
+
+  /**
+   * A 32-bit integer value
+   * 
+   * @type integer
+   */
+  public int getInteger() {
+    if (getSetField() == _Fields.INTEGER) {
+      return (java.lang.Integer)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'integer' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A 32-bit integer value
+   * 
+   * @type integer
+   */
+  public void setInteger(int value) {
+    setField_ = _Fields.INTEGER;
+    value_ = value;
+  }
+
+  /**
+   * A 64-bit integer value
+   * 
+   * @type integer:
+   *         precision:
+   *           bits: 64
+   */
+  public long getLongEsc() {
+    if (getSetField() == _Fields.LONG_ESC) {
+      return (java.lang.Long)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'longEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A 64-bit integer value
+   * 
+   * @type integer:
+   *         precision:
+   *           bits: 64
+   */
+  public void setLongEsc(long value) {
+    setField_ = _Fields.LONG_ESC;
+    value_ = value;
+  }
+
+  /**
+   * A string value
+   * 
+   * @type string
+   */
+  public java.lang.String getStringEsc() {
+    if (getSetField() == _Fields.STRING_ESC) {
+      return (java.lang.String)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'stringEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A string value
+   * 
+   * @type string
+   */
+  public void setStringEsc(java.lang.String value) {
+    setField_ = _Fields.STRING_ESC;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.STRING_ESC");
+  }
+
+  public boolean isSetBooleanEsc() {
+    return setField_ == _Fields.BOOLEAN_ESC;
+  }
+
+
+  public boolean isSetByteEsc() {
+    return setField_ == _Fields.BYTE_ESC;
+  }
+
+
+  public boolean isSetDoubleEsc() {
+    return setField_ == _Fields.DOUBLE_ESC;
+  }
+
+
+  public boolean isSetFloatEsc() {
+    return setField_ == _Fields.FLOAT_ESC;
+  }
+
+
+  public boolean isSetInteger() {
+    return setField_ == _Fields.INTEGER;
+  }
+
+
+  public boolean isSetLongEsc() {
+    return setField_ == _Fields.LONG_ESC;
+  }
+
+
+  public boolean isSetStringEsc() {
+    return setField_ == _Fields.STRING_ESC;
+  }
+
+
+  public boolean equals(java.lang.Object other) {
+    if (other instanceof AtomicValue) {
+      return equals((AtomicValue)other);
+    } else {
+      return false;
+    }
+  }
+
+  public boolean equals(AtomicValue other) {
+    return other != null && getSetField() == other.getSetField() && getFieldValue().equals(other.getFieldValue());
+  }
+
+  @Override
+  public int compareTo(AtomicValue other) {
+    int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), other.getSetField());
+    if (lastComparison == 0) {
+      return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());
+    }
+    return lastComparison;
+  }
+
+
+  @Override
+  public int hashCode() {
+    java.util.List<java.lang.Object> list = new java.util.ArrayList<java.lang.Object>();
+    list.add(this.getClass().getName());
+    org.apache.thrift.TFieldIdEnum setField = getSetField();
+    if (setField != null) {
+      list.add(setField.getThriftFieldId());
+      java.lang.Object value = getFieldValue();
+      if (value instanceof org.apache.thrift.TEnum) {
+        list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());
+      } else {
+        list.add(value);
+      }
+    }
+    return list.hashCode();
+  }
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Edge.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Edge.java
new file mode 100644
index 0000000..0a42290
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Edge.java
@@ -0,0 +1,940 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A edge, or binary relationship connecting two vertices
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class Edge implements org.apache.thrift.TBase<Edge, Edge._Fields>, java.io.Serializable, Cloneable, Comparable<Edge> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Edge");
+
+  private static final org.apache.thrift.protocol.TField ID_FIELD_DESC = new org.apache.thrift.protocol.TField("id", org.apache.thrift.protocol.TType.STRUCT, (short)1);
+  private static final org.apache.thrift.protocol.TField LABEL_FIELD_DESC = new org.apache.thrift.protocol.TField("label", org.apache.thrift.protocol.TType.STRING, (short)2);
+  private static final org.apache.thrift.protocol.TField PROPERTIES_FIELD_DESC = new org.apache.thrift.protocol.TField("properties", org.apache.thrift.protocol.TType.SET, (short)3);
+  private static final org.apache.thrift.protocol.TField OUT_VERTEX_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("outVertexId", org.apache.thrift.protocol.TType.STRUCT, (short)4);
+  private static final org.apache.thrift.protocol.TField IN_VERTEX_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("inVertexId", org.apache.thrift.protocol.TType.STRUCT, (short)5);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new EdgeStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new EdgeTupleSchemeFactory();
+
+  /**
+   * The unique id of the edge; no two edges in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeId
+   * @unique true
+   */
+  public @org.apache.thrift.annotation.Nullable AtomicValue id; // required
+  /**
+   * The label of the edge, sometimes indicating its type
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeLabel
+   */
+  public @org.apache.thrift.annotation.Nullable java.lang.String label; // required
+  /**
+   * Any properties (key/value pairs) of the edge
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public @org.apache.thrift.annotation.Nullable java.util.Set<Property> properties; // required
+  /**
+   * The id of the edge's out-vertex (tail)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  public @org.apache.thrift.annotation.Nullable AtomicValue outVertexId; // required
+  /**
+   * The id if the edge's in-vertex (head)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  public @org.apache.thrift.annotation.Nullable AtomicValue inVertexId; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * The unique id of the edge; no two edges in a graph may share the same id
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeId
+     * @unique true
+     */
+    ID((short)1, "id"),
+    /**
+     * The label of the edge, sometimes indicating its type
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeLabel
+     */
+    LABEL((short)2, "label"),
+    /**
+     * Any properties (key/value pairs) of the edge
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    PROPERTIES((short)3, "properties"),
+    /**
+     * The id of the edge's out-vertex (tail)
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     */
+    OUT_VERTEX_ID((short)4, "outVertexId"),
+    /**
+     * The id if the edge's in-vertex (head)
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     */
+    IN_VERTEX_ID((short)5, "inVertexId");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // ID
+          return ID;
+        case 2: // LABEL
+          return LABEL;
+        case 3: // PROPERTIES
+          return PROPERTIES;
+        case 4: // OUT_VERTEX_ID
+          return OUT_VERTEX_ID;
+        case 5: // IN_VERTEX_ID
+          return IN_VERTEX_ID;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.ID, new org.apache.thrift.meta_data.FieldMetaData("id", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT        , "EdgeId")));
+    tmpMap.put(_Fields.LABEL, new org.apache.thrift.meta_data.FieldMetaData("label", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , "EdgeLabel")));
+    tmpMap.put(_Fields.PROPERTIES, new org.apache.thrift.meta_data.FieldMetaData("properties", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Property.class))));
+    tmpMap.put(_Fields.OUT_VERTEX_ID, new org.apache.thrift.meta_data.FieldMetaData("outVertexId", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT        , "VertexId")));
+    tmpMap.put(_Fields.IN_VERTEX_ID, new org.apache.thrift.meta_data.FieldMetaData("inVertexId", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT        , "VertexId")));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Edge.class, metaDataMap);
+  }
+
+  public Edge() {
+  }
+
+  public Edge(
+    AtomicValue id,
+    java.lang.String label,
+    java.util.Set<Property> properties,
+    AtomicValue outVertexId,
+    AtomicValue inVertexId)
+  {
+    this();
+    this.id = id;
+    this.label = label;
+    this.properties = properties;
+    this.outVertexId = outVertexId;
+    this.inVertexId = inVertexId;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public Edge(Edge other) {
+    if (other.isSetId()) {
+      this.id = new AtomicValue(other.id);
+    }
+    if (other.isSetLabel()) {
+      this.label = other.label;
+    }
+    if (other.isSetProperties()) {
+      java.util.Set<Property> __this__properties = new java.util.HashSet<Property>(other.properties.size());
+      for (Property other_element : other.properties) {
+        __this__properties.add(new Property(other_element));
+      }
+      this.properties = __this__properties;
+    }
+    if (other.isSetOutVertexId()) {
+      this.outVertexId = new AtomicValue(other.outVertexId);
+    }
+    if (other.isSetInVertexId()) {
+      this.inVertexId = new AtomicValue(other.inVertexId);
+    }
+  }
+
+  public Edge deepCopy() {
+    return new Edge(this);
+  }
+
+  @Override
+  public void clear() {
+    this.id = null;
+    this.label = null;
+    this.properties = null;
+    this.outVertexId = null;
+    this.inVertexId = null;
+  }
+
+  /**
+   * The unique id of the edge; no two edges in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeId
+   * @unique true
+   */
+  @org.apache.thrift.annotation.Nullable
+  public AtomicValue getId() {
+    return this.id;
+  }
+
+  /**
+   * The unique id of the edge; no two edges in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeId
+   * @unique true
+   */
+  public Edge setId(@org.apache.thrift.annotation.Nullable AtomicValue id) {
+    this.id = id;
+    return this;
+  }
+
+  public void unsetId() {
+    this.id = null;
+  }
+
+  /** Returns true if field id is set (has been assigned a value) and false otherwise */
+  public boolean isSetId() {
+    return this.id != null;
+  }
+
+  public void setIdIsSet(boolean value) {
+    if (!value) {
+      this.id = null;
+    }
+  }
+
+  /**
+   * The label of the edge, sometimes indicating its type
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeLabel
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getLabel() {
+    return this.label;
+  }
+
+  /**
+   * The label of the edge, sometimes indicating its type
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeLabel
+   */
+  public Edge setLabel(@org.apache.thrift.annotation.Nullable java.lang.String label) {
+    this.label = label;
+    return this;
+  }
+
+  public void unsetLabel() {
+    this.label = null;
+  }
+
+  /** Returns true if field label is set (has been assigned a value) and false otherwise */
+  public boolean isSetLabel() {
+    return this.label != null;
+  }
+
+  public void setLabelIsSet(boolean value) {
+    if (!value) {
+      this.label = null;
+    }
+  }
+
+  public int getPropertiesSize() {
+    return (this.properties == null) ? 0 : this.properties.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Property> getPropertiesIterator() {
+    return (this.properties == null) ? null : this.properties.iterator();
+  }
+
+  public void addToProperties(Property elem) {
+    if (this.properties == null) {
+      this.properties = new java.util.HashSet<Property>();
+    }
+    this.properties.add(elem);
+  }
+
+  /**
+   * Any properties (key/value pairs) of the edge
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Set<Property> getProperties() {
+    return this.properties;
+  }
+
+  /**
+   * Any properties (key/value pairs) of the edge
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public Edge setProperties(@org.apache.thrift.annotation.Nullable java.util.Set<Property> properties) {
+    this.properties = properties;
+    return this;
+  }
+
+  public void unsetProperties() {
+    this.properties = null;
+  }
+
+  /** Returns true if field properties is set (has been assigned a value) and false otherwise */
+  public boolean isSetProperties() {
+    return this.properties != null;
+  }
+
+  public void setPropertiesIsSet(boolean value) {
+    if (!value) {
+      this.properties = null;
+    }
+  }
+
+  /**
+   * The id of the edge's out-vertex (tail)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  @org.apache.thrift.annotation.Nullable
+  public AtomicValue getOutVertexId() {
+    return this.outVertexId;
+  }
+
+  /**
+   * The id of the edge's out-vertex (tail)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  public Edge setOutVertexId(@org.apache.thrift.annotation.Nullable AtomicValue outVertexId) {
+    this.outVertexId = outVertexId;
+    return this;
+  }
+
+  public void unsetOutVertexId() {
+    this.outVertexId = null;
+  }
+
+  /** Returns true if field outVertexId is set (has been assigned a value) and false otherwise */
+  public boolean isSetOutVertexId() {
+    return this.outVertexId != null;
+  }
+
+  public void setOutVertexIdIsSet(boolean value) {
+    if (!value) {
+      this.outVertexId = null;
+    }
+  }
+
+  /**
+   * The id if the edge's in-vertex (head)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  @org.apache.thrift.annotation.Nullable
+  public AtomicValue getInVertexId() {
+    return this.inVertexId;
+  }
+
+  /**
+   * The id if the edge's in-vertex (head)
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   */
+  public Edge setInVertexId(@org.apache.thrift.annotation.Nullable AtomicValue inVertexId) {
+    this.inVertexId = inVertexId;
+    return this;
+  }
+
+  public void unsetInVertexId() {
+    this.inVertexId = null;
+  }
+
+  /** Returns true if field inVertexId is set (has been assigned a value) and false otherwise */
+  public boolean isSetInVertexId() {
+    return this.inVertexId != null;
+  }
+
+  public void setInVertexIdIsSet(boolean value) {
+    if (!value) {
+      this.inVertexId = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case ID:
+      if (value == null) {
+        unsetId();
+      } else {
+        setId((AtomicValue)value);
+      }
+      break;
+
+    case LABEL:
+      if (value == null) {
+        unsetLabel();
+      } else {
+        setLabel((java.lang.String)value);
+      }
+      break;
+
+    case PROPERTIES:
+      if (value == null) {
+        unsetProperties();
+      } else {
+        setProperties((java.util.Set<Property>)value);
+      }
+      break;
+
+    case OUT_VERTEX_ID:
+      if (value == null) {
+        unsetOutVertexId();
+      } else {
+        setOutVertexId((AtomicValue)value);
+      }
+      break;
+
+    case IN_VERTEX_ID:
+      if (value == null) {
+        unsetInVertexId();
+      } else {
+        setInVertexId((AtomicValue)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case ID:
+      return getId();
+
+    case LABEL:
+      return getLabel();
+
+    case PROPERTIES:
+      return getProperties();
+
+    case OUT_VERTEX_ID:
+      return getOutVertexId();
+
+    case IN_VERTEX_ID:
+      return getInVertexId();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case ID:
+      return isSetId();
+    case LABEL:
+      return isSetLabel();
+    case PROPERTIES:
+      return isSetProperties();
+    case OUT_VERTEX_ID:
+      return isSetOutVertexId();
+    case IN_VERTEX_ID:
+      return isSetInVertexId();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof Edge)
+      return this.equals((Edge)that);
+    return false;
+  }
+
+  public boolean equals(Edge that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_id = true && this.isSetId();
+    boolean that_present_id = true && that.isSetId();
+    if (this_present_id || that_present_id) {
+      if (!(this_present_id && that_present_id))
+        return false;
+      if (!this.id.equals(that.id))
+        return false;
+    }
+
+    boolean this_present_label = true && this.isSetLabel();
+    boolean that_present_label = true && that.isSetLabel();
+    if (this_present_label || that_present_label) {
+      if (!(this_present_label && that_present_label))
+        return false;
+      if (!this.label.equals(that.label))
+        return false;
+    }
+
+    boolean this_present_properties = true && this.isSetProperties();
+    boolean that_present_properties = true && that.isSetProperties();
+    if (this_present_properties || that_present_properties) {
+      if (!(this_present_properties && that_present_properties))
+        return false;
+      if (!this.properties.equals(that.properties))
+        return false;
+    }
+
+    boolean this_present_outVertexId = true && this.isSetOutVertexId();
+    boolean that_present_outVertexId = true && that.isSetOutVertexId();
+    if (this_present_outVertexId || that_present_outVertexId) {
+      if (!(this_present_outVertexId && that_present_outVertexId))
+        return false;
+      if (!this.outVertexId.equals(that.outVertexId))
+        return false;
+    }
+
+    boolean this_present_inVertexId = true && this.isSetInVertexId();
+    boolean that_present_inVertexId = true && that.isSetInVertexId();
+    if (this_present_inVertexId || that_present_inVertexId) {
+      if (!(this_present_inVertexId && that_present_inVertexId))
+        return false;
+      if (!this.inVertexId.equals(that.inVertexId))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetId()) ? 131071 : 524287);
+    if (isSetId())
+      hashCode = hashCode * 8191 + id.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetLabel()) ? 131071 : 524287);
+    if (isSetLabel())
+      hashCode = hashCode * 8191 + label.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetProperties()) ? 131071 : 524287);
+    if (isSetProperties())
+      hashCode = hashCode * 8191 + properties.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetOutVertexId()) ? 131071 : 524287);
+    if (isSetOutVertexId())
+      hashCode = hashCode * 8191 + outVertexId.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetInVertexId()) ? 131071 : 524287);
+    if (isSetInVertexId())
+      hashCode = hashCode * 8191 + inVertexId.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(Edge other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetId(), other.isSetId());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetId()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.id, other.id);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetLabel(), other.isSetLabel());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetLabel()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.label, other.label);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetProperties(), other.isSetProperties());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetProperties()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.properties, other.properties);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetOutVertexId(), other.isSetOutVertexId());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetOutVertexId()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.outVertexId, other.outVertexId);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetInVertexId(), other.isSetInVertexId());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetInVertexId()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.inVertexId, other.inVertexId);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("Edge(");
+    boolean first = true;
+
+    sb.append("id:");
+    if (this.id == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.id);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("label:");
+    if (this.label == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.label);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("properties:");
+    if (this.properties == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.properties);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("outVertexId:");
+    if (this.outVertexId == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.outVertexId);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("inVertexId:");
+    if (this.inVertexId == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.inVertexId);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    if (id == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'id' was not present! Struct: " + toString());
+    }
+    if (label == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'label' was not present! Struct: " + toString());
+    }
+    if (properties == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'properties' was not present! Struct: " + toString());
+    }
+    if (outVertexId == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'outVertexId' was not present! Struct: " + toString());
+    }
+    if (inVertexId == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'inVertexId' was not present! Struct: " + toString());
+    }
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class EdgeStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public EdgeStandardScheme getScheme() {
+      return new EdgeStandardScheme();
+    }
+  }
+
+  private static class EdgeStandardScheme extends org.apache.thrift.scheme.StandardScheme<Edge> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, Edge struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // ID
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+              struct.id = new AtomicValue();
+              struct.id.read(iprot);
+              struct.setIdIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // LABEL
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.label = iprot.readString();
+              struct.setLabelIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 3: // PROPERTIES
+            if (schemeField.type == org.apache.thrift.protocol.TType.SET) {
+              {
+                org.apache.thrift.protocol.TSet _set42 = iprot.readSetBegin();
+                struct.properties = new java.util.HashSet<Property>(2*_set42.size);
+                @org.apache.thrift.annotation.Nullable Property _elem43;
+                for (int _i44 = 0; _i44 < _set42.size; ++_i44)
+                {
+                  _elem43 = new Property();
+                  _elem43.read(iprot);
+                  struct.properties.add(_elem43);
+                }
+                iprot.readSetEnd();
+              }
+              struct.setPropertiesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 4: // OUT_VERTEX_ID
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+              struct.outVertexId = new AtomicValue();
+              struct.outVertexId.read(iprot);
+              struct.setOutVertexIdIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 5: // IN_VERTEX_ID
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+              struct.inVertexId = new AtomicValue();
+              struct.inVertexId.read(iprot);
+              struct.setInVertexIdIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, Edge struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.id != null) {
+        oprot.writeFieldBegin(ID_FIELD_DESC);
+        struct.id.write(oprot);
+        oprot.writeFieldEnd();
+      }
+      if (struct.label != null) {
+        oprot.writeFieldBegin(LABEL_FIELD_DESC);
+        oprot.writeString(struct.label);
+        oprot.writeFieldEnd();
+      }
+      if (struct.properties != null) {
+        oprot.writeFieldBegin(PROPERTIES_FIELD_DESC);
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, struct.properties.size()));
+          for (Property _iter45 : struct.properties)
+          {
+            _iter45.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      if (struct.outVertexId != null) {
+        oprot.writeFieldBegin(OUT_VERTEX_ID_FIELD_DESC);
+        struct.outVertexId.write(oprot);
+        oprot.writeFieldEnd();
+      }
+      if (struct.inVertexId != null) {
+        oprot.writeFieldBegin(IN_VERTEX_ID_FIELD_DESC);
+        struct.inVertexId.write(oprot);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class EdgeTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public EdgeTupleScheme getScheme() {
+      return new EdgeTupleScheme();
+    }
+  }
+
+  private static class EdgeTupleScheme extends org.apache.thrift.scheme.TupleScheme<Edge> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, Edge struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      struct.id.write(oprot);
+      oprot.writeString(struct.label);
+      {
+        oprot.writeI32(struct.properties.size());
+        for (Property _iter46 : struct.properties)
+        {
+          _iter46.write(oprot);
+        }
+      }
+      struct.outVertexId.write(oprot);
+      struct.inVertexId.write(oprot);
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, Edge struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      struct.id = new AtomicValue();
+      struct.id.read(iprot);
+      struct.setIdIsSet(true);
+      struct.label = iprot.readString();
+      struct.setLabelIsSet(true);
+      {
+        org.apache.thrift.protocol.TSet _set47 = iprot.readSetBegin(org.apache.thrift.protocol.TType.STRUCT);
+        struct.properties = new java.util.HashSet<Property>(2*_set47.size);
+        @org.apache.thrift.annotation.Nullable Property _elem48;
+        for (int _i49 = 0; _i49 < _set47.size; ++_i49)
+        {
+          _elem48 = new Property();
+          _elem48.read(iprot);
+          struct.properties.add(_elem48);
+        }
+      }
+      struct.setPropertiesIsSet(true);
+      struct.outVertexId = new AtomicValue();
+      struct.outVertexId.read(iprot);
+      struct.setOutVertexIdIsSet(true);
+      struct.inVertexId = new AtomicValue();
+      struct.inVertexId.read(iprot);
+      struct.setInVertexIdIsSet(true);
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Graph.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Graph.java
new file mode 100644
index 0000000..c6fda05
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Graph.java
@@ -0,0 +1,624 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A graph, consisting of a set of vertices and a set of edges
+ * 
+ * @comments As a basic integrity constraint, the out- and in- vertex ids of the graph's edges must be among the ids of the graph's vertices.
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class Graph implements org.apache.thrift.TBase<Graph, Graph._Fields>, java.io.Serializable, Cloneable, Comparable<Graph> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Graph");
+
+  private static final org.apache.thrift.protocol.TField VERTICES_FIELD_DESC = new org.apache.thrift.protocol.TField("vertices", org.apache.thrift.protocol.TType.SET, (short)1);
+  private static final org.apache.thrift.protocol.TField EDGES_FIELD_DESC = new org.apache.thrift.protocol.TField("edges", org.apache.thrift.protocol.TType.SET, (short)2);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new GraphStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new GraphTupleSchemeFactory();
+
+  /**
+   * The set of all vertices in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Vertex
+   */
+  public @org.apache.thrift.annotation.Nullable java.util.Set<Vertex> vertices; // required
+  /**
+   * The set of all edges in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Edge
+   */
+  public @org.apache.thrift.annotation.Nullable java.util.Set<Edge> edges; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * The set of all vertices in the graph
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Vertex
+     */
+    VERTICES((short)1, "vertices"),
+    /**
+     * The set of all edges in the graph
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Edge
+     */
+    EDGES((short)2, "edges");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // VERTICES
+          return VERTICES;
+        case 2: // EDGES
+          return EDGES;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.VERTICES, new org.apache.thrift.meta_data.FieldMetaData("vertices", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Vertex.class))));
+    tmpMap.put(_Fields.EDGES, new org.apache.thrift.meta_data.FieldMetaData("edges", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Edge.class))));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Graph.class, metaDataMap);
+  }
+
+  public Graph() {
+  }
+
+  public Graph(
+    java.util.Set<Vertex> vertices,
+    java.util.Set<Edge> edges)
+  {
+    this();
+    this.vertices = vertices;
+    this.edges = edges;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public Graph(Graph other) {
+    if (other.isSetVertices()) {
+      java.util.Set<Vertex> __this__vertices = new java.util.HashSet<Vertex>(other.vertices.size());
+      for (Vertex other_element : other.vertices) {
+        __this__vertices.add(new Vertex(other_element));
+      }
+      this.vertices = __this__vertices;
+    }
+    if (other.isSetEdges()) {
+      java.util.Set<Edge> __this__edges = new java.util.HashSet<Edge>(other.edges.size());
+      for (Edge other_element : other.edges) {
+        __this__edges.add(new Edge(other_element));
+      }
+      this.edges = __this__edges;
+    }
+  }
+
+  public Graph deepCopy() {
+    return new Graph(this);
+  }
+
+  @Override
+  public void clear() {
+    this.vertices = null;
+    this.edges = null;
+  }
+
+  public int getVerticesSize() {
+    return (this.vertices == null) ? 0 : this.vertices.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Vertex> getVerticesIterator() {
+    return (this.vertices == null) ? null : this.vertices.iterator();
+  }
+
+  public void addToVertices(Vertex elem) {
+    if (this.vertices == null) {
+      this.vertices = new java.util.HashSet<Vertex>();
+    }
+    this.vertices.add(elem);
+  }
+
+  /**
+   * The set of all vertices in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Vertex
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Set<Vertex> getVertices() {
+    return this.vertices;
+  }
+
+  /**
+   * The set of all vertices in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Vertex
+   */
+  public Graph setVertices(@org.apache.thrift.annotation.Nullable java.util.Set<Vertex> vertices) {
+    this.vertices = vertices;
+    return this;
+  }
+
+  public void unsetVertices() {
+    this.vertices = null;
+  }
+
+  /** Returns true if field vertices is set (has been assigned a value) and false otherwise */
+  public boolean isSetVertices() {
+    return this.vertices != null;
+  }
+
+  public void setVerticesIsSet(boolean value) {
+    if (!value) {
+      this.vertices = null;
+    }
+  }
+
+  public int getEdgesSize() {
+    return (this.edges == null) ? 0 : this.edges.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Edge> getEdgesIterator() {
+    return (this.edges == null) ? null : this.edges.iterator();
+  }
+
+  public void addToEdges(Edge elem) {
+    if (this.edges == null) {
+      this.edges = new java.util.HashSet<Edge>();
+    }
+    this.edges.add(elem);
+  }
+
+  /**
+   * The set of all edges in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Edge
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Set<Edge> getEdges() {
+    return this.edges;
+  }
+
+  /**
+   * The set of all edges in the graph
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Edge
+   */
+  public Graph setEdges(@org.apache.thrift.annotation.Nullable java.util.Set<Edge> edges) {
+    this.edges = edges;
+    return this;
+  }
+
+  public void unsetEdges() {
+    this.edges = null;
+  }
+
+  /** Returns true if field edges is set (has been assigned a value) and false otherwise */
+  public boolean isSetEdges() {
+    return this.edges != null;
+  }
+
+  public void setEdgesIsSet(boolean value) {
+    if (!value) {
+      this.edges = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case VERTICES:
+      if (value == null) {
+        unsetVertices();
+      } else {
+        setVertices((java.util.Set<Vertex>)value);
+      }
+      break;
+
+    case EDGES:
+      if (value == null) {
+        unsetEdges();
+      } else {
+        setEdges((java.util.Set<Edge>)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case VERTICES:
+      return getVertices();
+
+    case EDGES:
+      return getEdges();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case VERTICES:
+      return isSetVertices();
+    case EDGES:
+      return isSetEdges();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof Graph)
+      return this.equals((Graph)that);
+    return false;
+  }
+
+  public boolean equals(Graph that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_vertices = true && this.isSetVertices();
+    boolean that_present_vertices = true && that.isSetVertices();
+    if (this_present_vertices || that_present_vertices) {
+      if (!(this_present_vertices && that_present_vertices))
+        return false;
+      if (!this.vertices.equals(that.vertices))
+        return false;
+    }
+
+    boolean this_present_edges = true && this.isSetEdges();
+    boolean that_present_edges = true && that.isSetEdges();
+    if (this_present_edges || that_present_edges) {
+      if (!(this_present_edges && that_present_edges))
+        return false;
+      if (!this.edges.equals(that.edges))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetVertices()) ? 131071 : 524287);
+    if (isSetVertices())
+      hashCode = hashCode * 8191 + vertices.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetEdges()) ? 131071 : 524287);
+    if (isSetEdges())
+      hashCode = hashCode * 8191 + edges.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(Graph other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetVertices(), other.isSetVertices());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetVertices()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.vertices, other.vertices);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetEdges(), other.isSetEdges());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetEdges()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.edges, other.edges);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("Graph(");
+    boolean first = true;
+
+    sb.append("vertices:");
+    if (this.vertices == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.vertices);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("edges:");
+    if (this.edges == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.edges);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    if (vertices == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'vertices' was not present! Struct: " + toString());
+    }
+    if (edges == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'edges' was not present! Struct: " + toString());
+    }
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class GraphStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public GraphStandardScheme getScheme() {
+      return new GraphStandardScheme();
+    }
+  }
+
+  private static class GraphStandardScheme extends org.apache.thrift.scheme.StandardScheme<Graph> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, Graph struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // VERTICES
+            if (schemeField.type == org.apache.thrift.protocol.TType.SET) {
+              {
+                org.apache.thrift.protocol.TSet _set58 = iprot.readSetBegin();
+                struct.vertices = new java.util.HashSet<Vertex>(2*_set58.size);
+                @org.apache.thrift.annotation.Nullable Vertex _elem59;
+                for (int _i60 = 0; _i60 < _set58.size; ++_i60)
+                {
+                  _elem59 = new Vertex();
+                  _elem59.read(iprot);
+                  struct.vertices.add(_elem59);
+                }
+                iprot.readSetEnd();
+              }
+              struct.setVerticesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // EDGES
+            if (schemeField.type == org.apache.thrift.protocol.TType.SET) {
+              {
+                org.apache.thrift.protocol.TSet _set61 = iprot.readSetBegin();
+                struct.edges = new java.util.HashSet<Edge>(2*_set61.size);
+                @org.apache.thrift.annotation.Nullable Edge _elem62;
+                for (int _i63 = 0; _i63 < _set61.size; ++_i63)
+                {
+                  _elem62 = new Edge();
+                  _elem62.read(iprot);
+                  struct.edges.add(_elem62);
+                }
+                iprot.readSetEnd();
+              }
+              struct.setEdgesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, Graph struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.vertices != null) {
+        oprot.writeFieldBegin(VERTICES_FIELD_DESC);
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, struct.vertices.size()));
+          for (Vertex _iter64 : struct.vertices)
+          {
+            _iter64.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      if (struct.edges != null) {
+        oprot.writeFieldBegin(EDGES_FIELD_DESC);
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, struct.edges.size()));
+          for (Edge _iter65 : struct.edges)
+          {
+            _iter65.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class GraphTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public GraphTupleScheme getScheme() {
+      return new GraphTupleScheme();
+    }
+  }
+
+  private static class GraphTupleScheme extends org.apache.thrift.scheme.TupleScheme<Graph> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, Graph struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      {
+        oprot.writeI32(struct.vertices.size());
+        for (Vertex _iter66 : struct.vertices)
+        {
+          _iter66.write(oprot);
+        }
+      }
+      {
+        oprot.writeI32(struct.edges.size());
+        for (Edge _iter67 : struct.edges)
+        {
+          _iter67.write(oprot);
+        }
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, Graph struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      {
+        org.apache.thrift.protocol.TSet _set68 = iprot.readSetBegin(org.apache.thrift.protocol.TType.STRUCT);
+        struct.vertices = new java.util.HashSet<Vertex>(2*_set68.size);
+        @org.apache.thrift.annotation.Nullable Vertex _elem69;
+        for (int _i70 = 0; _i70 < _set68.size; ++_i70)
+        {
+          _elem69 = new Vertex();
+          _elem69.read(iprot);
+          struct.vertices.add(_elem69);
+        }
+      }
+      struct.setVerticesIsSet(true);
+      {
+        org.apache.thrift.protocol.TSet _set71 = iprot.readSetBegin(org.apache.thrift.protocol.TType.STRUCT);
+        struct.edges = new java.util.HashSet<Edge>(2*_set71.size);
+        @org.apache.thrift.annotation.Nullable Edge _elem72;
+        for (int _i73 = 0; _i73 < _set71.size; ++_i73)
+        {
+          _elem72 = new Edge();
+          _elem72.read(iprot);
+          struct.edges.add(_elem72);
+        }
+      }
+      struct.setEdgesIsSet(true);
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Property.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Property.java
new file mode 100644
index 0000000..f02d9a0
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Property.java
@@ -0,0 +1,690 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A property, or key/value pair which may be attached to vertices, edges, and occasionally other properties.
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class Property implements org.apache.thrift.TBase<Property, Property._Fields>, java.io.Serializable, Cloneable, Comparable<Property> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Property");
+
+  private static final org.apache.thrift.protocol.TField KEY_FIELD_DESC = new org.apache.thrift.protocol.TField("key", org.apache.thrift.protocol.TType.STRING, (short)1);
+  private static final org.apache.thrift.protocol.TField VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("value", org.apache.thrift.protocol.TType.STRUCT, (short)2);
+  private static final org.apache.thrift.protocol.TField METAPROPERTIES_FIELD_DESC = new org.apache.thrift.protocol.TField("metaproperties", org.apache.thrift.protocol.TType.SET, (short)3);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new PropertyStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new PropertyTupleSchemeFactory();
+
+  /**
+   * The property's key
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.PropertyKey
+   */
+  public @org.apache.thrift.annotation.Nullable java.lang.String key; // required
+  /**
+   * The property's value
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public @org.apache.thrift.annotation.Nullable Value value; // required
+  /**
+   * Any metaproperties (properties of a property)
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public @org.apache.thrift.annotation.Nullable java.util.Set<Property> metaproperties; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * The property's key
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.PropertyKey
+     */
+    KEY((short)1, "key"),
+    /**
+     * The property's value
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    VALUE((short)2, "value"),
+    /**
+     * Any metaproperties (properties of a property)
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    METAPROPERTIES((short)3, "metaproperties");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // KEY
+          return KEY;
+        case 2: // VALUE
+          return VALUE;
+        case 3: // METAPROPERTIES
+          return METAPROPERTIES;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.KEY, new org.apache.thrift.meta_data.FieldMetaData("key", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , "PropertyKey")));
+    tmpMap.put(_Fields.VALUE, new org.apache.thrift.meta_data.FieldMetaData("value", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT        , "Value")));
+    tmpMap.put(_Fields.METAPROPERTIES, new org.apache.thrift.meta_data.FieldMetaData("metaproperties", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT            , "Property"))));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Property.class, metaDataMap);
+  }
+
+  public Property() {
+  }
+
+  public Property(
+    java.lang.String key,
+    Value value,
+    java.util.Set<Property> metaproperties)
+  {
+    this();
+    this.key = key;
+    this.value = value;
+    this.metaproperties = metaproperties;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public Property(Property other) {
+    if (other.isSetKey()) {
+      this.key = other.key;
+    }
+    if (other.isSetValue()) {
+      this.value = new Value(other.value);
+    }
+    if (other.isSetMetaproperties()) {
+      java.util.Set<Property> __this__metaproperties = new java.util.HashSet<Property>(other.metaproperties.size());
+      for (Property other_element : other.metaproperties) {
+        __this__metaproperties.add(new Property(other_element));
+      }
+      this.metaproperties = __this__metaproperties;
+    }
+  }
+
+  public Property deepCopy() {
+    return new Property(this);
+  }
+
+  @Override
+  public void clear() {
+    this.key = null;
+    this.value = null;
+    this.metaproperties = null;
+  }
+
+  /**
+   * The property's key
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.PropertyKey
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getKey() {
+    return this.key;
+  }
+
+  /**
+   * The property's key
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.PropertyKey
+   */
+  public Property setKey(@org.apache.thrift.annotation.Nullable java.lang.String key) {
+    this.key = key;
+    return this;
+  }
+
+  public void unsetKey() {
+    this.key = null;
+  }
+
+  /** Returns true if field key is set (has been assigned a value) and false otherwise */
+  public boolean isSetKey() {
+    return this.key != null;
+  }
+
+  public void setKeyIsSet(boolean value) {
+    if (!value) {
+      this.key = null;
+    }
+  }
+
+  /**
+   * The property's value
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  @org.apache.thrift.annotation.Nullable
+  public Value getValue() {
+    return this.value;
+  }
+
+  /**
+   * The property's value
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public Property setValue(@org.apache.thrift.annotation.Nullable Value value) {
+    this.value = value;
+    return this;
+  }
+
+  public void unsetValue() {
+    this.value = null;
+  }
+
+  /** Returns true if field value is set (has been assigned a value) and false otherwise */
+  public boolean isSetValue() {
+    return this.value != null;
+  }
+
+  public void setValueIsSet(boolean value) {
+    if (!value) {
+      this.value = null;
+    }
+  }
+
+  public int getMetapropertiesSize() {
+    return (this.metaproperties == null) ? 0 : this.metaproperties.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Property> getMetapropertiesIterator() {
+    return (this.metaproperties == null) ? null : this.metaproperties.iterator();
+  }
+
+  public void addToMetaproperties(Property elem) {
+    if (this.metaproperties == null) {
+      this.metaproperties = new java.util.HashSet<Property>();
+    }
+    this.metaproperties.add(elem);
+  }
+
+  /**
+   * Any metaproperties (properties of a property)
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Set<Property> getMetaproperties() {
+    return this.metaproperties;
+  }
+
+  /**
+   * Any metaproperties (properties of a property)
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public Property setMetaproperties(@org.apache.thrift.annotation.Nullable java.util.Set<Property> metaproperties) {
+    this.metaproperties = metaproperties;
+    return this;
+  }
+
+  public void unsetMetaproperties() {
+    this.metaproperties = null;
+  }
+
+  /** Returns true if field metaproperties is set (has been assigned a value) and false otherwise */
+  public boolean isSetMetaproperties() {
+    return this.metaproperties != null;
+  }
+
+  public void setMetapropertiesIsSet(boolean value) {
+    if (!value) {
+      this.metaproperties = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case KEY:
+      if (value == null) {
+        unsetKey();
+      } else {
+        setKey((java.lang.String)value);
+      }
+      break;
+
+    case VALUE:
+      if (value == null) {
+        unsetValue();
+      } else {
+        setValue((Value)value);
+      }
+      break;
+
+    case METAPROPERTIES:
+      if (value == null) {
+        unsetMetaproperties();
+      } else {
+        setMetaproperties((java.util.Set<Property>)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case KEY:
+      return getKey();
+
+    case VALUE:
+      return getValue();
+
+    case METAPROPERTIES:
+      return getMetaproperties();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case KEY:
+      return isSetKey();
+    case VALUE:
+      return isSetValue();
+    case METAPROPERTIES:
+      return isSetMetaproperties();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof Property)
+      return this.equals((Property)that);
+    return false;
+  }
+
+  public boolean equals(Property that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_key = true && this.isSetKey();
+    boolean that_present_key = true && that.isSetKey();
+    if (this_present_key || that_present_key) {
+      if (!(this_present_key && that_present_key))
+        return false;
+      if (!this.key.equals(that.key))
+        return false;
+    }
+
+    boolean this_present_value = true && this.isSetValue();
+    boolean that_present_value = true && that.isSetValue();
+    if (this_present_value || that_present_value) {
+      if (!(this_present_value && that_present_value))
+        return false;
+      if (!this.value.equals(that.value))
+        return false;
+    }
+
+    boolean this_present_metaproperties = true && this.isSetMetaproperties();
+    boolean that_present_metaproperties = true && that.isSetMetaproperties();
+    if (this_present_metaproperties || that_present_metaproperties) {
+      if (!(this_present_metaproperties && that_present_metaproperties))
+        return false;
+      if (!this.metaproperties.equals(that.metaproperties))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetKey()) ? 131071 : 524287);
+    if (isSetKey())
+      hashCode = hashCode * 8191 + key.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetValue()) ? 131071 : 524287);
+    if (isSetValue())
+      hashCode = hashCode * 8191 + value.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetMetaproperties()) ? 131071 : 524287);
+    if (isSetMetaproperties())
+      hashCode = hashCode * 8191 + metaproperties.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(Property other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetKey(), other.isSetKey());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetKey()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.key, other.key);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetValue(), other.isSetValue());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetValue()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.value, other.value);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetMetaproperties(), other.isSetMetaproperties());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMetaproperties()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.metaproperties, other.metaproperties);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("Property(");
+    boolean first = true;
+
+    sb.append("key:");
+    if (this.key == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.key);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("value:");
+    if (this.value == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.value);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("metaproperties:");
+    if (this.metaproperties == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.metaproperties);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    if (key == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'key' was not present! Struct: " + toString());
+    }
+    if (value == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'value' was not present! Struct: " + toString());
+    }
+    if (metaproperties == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'metaproperties' was not present! Struct: " + toString());
+    }
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class PropertyStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public PropertyStandardScheme getScheme() {
+      return new PropertyStandardScheme();
+    }
+  }
+
+  private static class PropertyStandardScheme extends org.apache.thrift.scheme.StandardScheme<Property> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, Property struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // KEY
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.key = iprot.readString();
+              struct.setKeyIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // VALUE
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+              struct.value = new Value();
+              struct.value.read(iprot);
+              struct.setValueIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 3: // METAPROPERTIES
+            if (schemeField.type == org.apache.thrift.protocol.TType.SET) {
+              {
+                org.apache.thrift.protocol.TSet _set0 = iprot.readSetBegin();
+                struct.metaproperties = new java.util.HashSet<Property>(2*_set0.size);
+                @org.apache.thrift.annotation.Nullable Property _elem1;
+                for (int _i2 = 0; _i2 < _set0.size; ++_i2)
+                {
+                  _elem1 = new Property();
+                  _elem1.read(iprot);
+                  struct.metaproperties.add(_elem1);
+                }
+                iprot.readSetEnd();
+              }
+              struct.setMetapropertiesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, Property struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.key != null) {
+        oprot.writeFieldBegin(KEY_FIELD_DESC);
+        oprot.writeString(struct.key);
+        oprot.writeFieldEnd();
+      }
+      if (struct.value != null) {
+        oprot.writeFieldBegin(VALUE_FIELD_DESC);
+        struct.value.write(oprot);
+        oprot.writeFieldEnd();
+      }
+      if (struct.metaproperties != null) {
+        oprot.writeFieldBegin(METAPROPERTIES_FIELD_DESC);
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, struct.metaproperties.size()));
+          for (Property _iter3 : struct.metaproperties)
+          {
+            _iter3.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class PropertyTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public PropertyTupleScheme getScheme() {
+      return new PropertyTupleScheme();
+    }
+  }
+
+  private static class PropertyTupleScheme extends org.apache.thrift.scheme.TupleScheme<Property> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, Property struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      oprot.writeString(struct.key);
+      struct.value.write(oprot);
+      {
+        oprot.writeI32(struct.metaproperties.size());
+        for (Property _iter4 : struct.metaproperties)
+        {
+          _iter4.write(oprot);
+        }
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, Property struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      struct.key = iprot.readString();
+      struct.setKeyIsSet(true);
+      struct.value = new Value();
+      struct.value.read(iprot);
+      struct.setValueIsSet(true);
+      {
+        org.apache.thrift.protocol.TSet _set5 = iprot.readSetBegin(org.apache.thrift.protocol.TType.STRUCT);
+        struct.metaproperties = new java.util.HashSet<Property>(2*_set5.size);
+        @org.apache.thrift.annotation.Nullable Property _elem6;
+        for (int _i7 = 0; _i7 < _set5.size; ++_i7)
+        {
+          _elem6 = new Property();
+          _elem6.read(iprot);
+          struct.metaproperties.add(_elem6);
+        }
+      }
+      struct.setMetapropertiesIsSet(true);
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Value.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Value.java
new file mode 100644
index 0000000..5634fb3
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Value.java
@@ -0,0 +1,829 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * An id or property value; either an atomic (simple) value, or a list, map, or set value
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class Value extends org.apache.thrift.TUnion<Value, Value._Fields> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Value");
+  private static final org.apache.thrift.protocol.TField ATOMIC_FIELD_DESC = new org.apache.thrift.protocol.TField("atomic", org.apache.thrift.protocol.TType.STRUCT, (short)1);
+  private static final org.apache.thrift.protocol.TField LIST_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("listEsc", org.apache.thrift.protocol.TType.LIST, (short)2);
+  private static final org.apache.thrift.protocol.TField ARRAY_FIELD_DESC = new org.apache.thrift.protocol.TField("array", org.apache.thrift.protocol.TType.LIST, (short)3);
+  private static final org.apache.thrift.protocol.TField MAP_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("mapEsc", org.apache.thrift.protocol.TType.MAP, (short)4);
+  private static final org.apache.thrift.protocol.TField SET_ESC_FIELD_DESC = new org.apache.thrift.protocol.TField("setEsc", org.apache.thrift.protocol.TType.SET, (short)5);
+  private static final org.apache.thrift.protocol.TField SERIALIZED_FIELD_DESC = new org.apache.thrift.protocol.TField("serialized", org.apache.thrift.protocol.TType.STRING, (short)6);
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * An atomic (simple) value
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+     */
+    ATOMIC((short)1, "atomic"),
+    /**
+     * An ordered list value
+     * 
+     * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    LIST_ESC((short)2, "listEsc"),
+    /**
+     * An array value. Like a list, but also supporting efficient random access
+     * 
+     * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    ARRAY((short)3, "array"),
+    /**
+     * A map of arbitrary string keys to arbitrary values
+     * 
+     * @type map:
+     *         keys: string
+     *         values: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    MAP_ESC((short)4, "mapEsc"),
+    /**
+     * A set of unique values
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    SET_ESC((short)5, "setEsc"),
+    /**
+     * A serialized object which the application should be capable of decoding
+     * 
+     * @type string
+     */
+    SERIALIZED((short)6, "serialized");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // ATOMIC
+          return ATOMIC;
+        case 2: // LIST_ESC
+          return LIST_ESC;
+        case 3: // ARRAY
+          return ARRAY;
+        case 4: // MAP_ESC
+          return MAP_ESC;
+        case 5: // SET_ESC
+          return SET_ESC;
+        case 6: // SERIALIZED
+          return SERIALIZED;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.ATOMIC, new org.apache.thrift.meta_data.FieldMetaData("atomic", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, AtomicValue.class)));
+    tmpMap.put(_Fields.LIST_ESC, new org.apache.thrift.meta_data.FieldMetaData("listEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT            , "Value"))));
+    tmpMap.put(_Fields.ARRAY, new org.apache.thrift.meta_data.FieldMetaData("array", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT            , "Value"))));
+    tmpMap.put(_Fields.MAP_ESC, new org.apache.thrift.meta_data.FieldMetaData("mapEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING), 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT            , "Value"))));
+    tmpMap.put(_Fields.SET_ESC, new org.apache.thrift.meta_data.FieldMetaData("setEsc", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT            , "Value"))));
+    tmpMap.put(_Fields.SERIALIZED, new org.apache.thrift.meta_data.FieldMetaData("serialized", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Value.class, metaDataMap);
+  }
+
+  public Value() {
+    super();
+  }
+
+  public Value(_Fields setField, java.lang.Object value) {
+    super(setField, value);
+  }
+
+  public Value(Value other) {
+    super(other);
+  }
+  public Value deepCopy() {
+    return new Value(this);
+  }
+
+  public static Value atomic(AtomicValue value) {
+    Value x = new Value();
+    x.setAtomic(value);
+    return x;
+  }
+
+  public static Value listEsc(java.util.List<Value> value) {
+    Value x = new Value();
+    x.setListEsc(value);
+    return x;
+  }
+
+  public static Value array(java.util.List<Value> value) {
+    Value x = new Value();
+    x.setArray(value);
+    return x;
+  }
+
+  public static Value mapEsc(java.util.Map<java.lang.String,Value> value) {
+    Value x = new Value();
+    x.setMapEsc(value);
+    return x;
+  }
+
+  public static Value setEsc(java.util.Set<Value> value) {
+    Value x = new Value();
+    x.setSetEsc(value);
+    return x;
+  }
+
+  public static Value serialized(java.lang.String value) {
+    Value x = new Value();
+    x.setSerialized(value);
+    return x;
+  }
+
+
+  @Override
+  protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException {
+    switch (setField) {
+      case ATOMIC:
+        if (value instanceof AtomicValue) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type AtomicValue for field 'atomic', but got " + value.getClass().getSimpleName());
+      case LIST_ESC:
+        if (value instanceof java.util.List) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.util.List<Value> for field 'listEsc', but got " + value.getClass().getSimpleName());
+      case ARRAY:
+        if (value instanceof java.util.List) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.util.List<Value> for field 'array', but got " + value.getClass().getSimpleName());
+      case MAP_ESC:
+        if (value instanceof java.util.Map) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.util.Map<java.lang.String,Value> for field 'mapEsc', but got " + value.getClass().getSimpleName());
+      case SET_ESC:
+        if (value instanceof java.util.Set) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.util.Set<Value> for field 'setEsc', but got " + value.getClass().getSimpleName());
+      case SERIALIZED:
+        if (value instanceof java.lang.String) {
+          break;
+        }
+        throw new java.lang.ClassCastException("Was expecting value of type java.lang.String for field 'serialized', but got " + value.getClass().getSimpleName());
+      default:
+        throw new java.lang.IllegalArgumentException("Unknown field id " + setField);
+    }
+  }
+
+  @Override
+  protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TField field) throws org.apache.thrift.TException {
+    _Fields setField = _Fields.findByThriftId(field.id);
+    if (setField != null) {
+      switch (setField) {
+        case ATOMIC:
+          if (field.type == ATOMIC_FIELD_DESC.type) {
+            AtomicValue atomic;
+            atomic = new AtomicValue();
+            atomic.read(iprot);
+            return atomic;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case LIST_ESC:
+          if (field.type == LIST_ESC_FIELD_DESC.type) {
+            java.util.List<Value> listEsc;
+            {
+              org.apache.thrift.protocol.TList _list8 = iprot.readListBegin();
+              listEsc = new java.util.ArrayList<Value>(_list8.size);
+              @org.apache.thrift.annotation.Nullable Value _elem9;
+              for (int _i10 = 0; _i10 < _list8.size; ++_i10)
+              {
+                _elem9 = new Value();
+                _elem9.read(iprot);
+                listEsc.add(_elem9);
+              }
+              iprot.readListEnd();
+            }
+            return listEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case ARRAY:
+          if (field.type == ARRAY_FIELD_DESC.type) {
+            java.util.List<Value> array;
+            {
+              org.apache.thrift.protocol.TList _list11 = iprot.readListBegin();
+              array = new java.util.ArrayList<Value>(_list11.size);
+              @org.apache.thrift.annotation.Nullable Value _elem12;
+              for (int _i13 = 0; _i13 < _list11.size; ++_i13)
+              {
+                _elem12 = new Value();
+                _elem12.read(iprot);
+                array.add(_elem12);
+              }
+              iprot.readListEnd();
+            }
+            return array;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case MAP_ESC:
+          if (field.type == MAP_ESC_FIELD_DESC.type) {
+            java.util.Map<java.lang.String,Value> mapEsc;
+            {
+              org.apache.thrift.protocol.TMap _map14 = iprot.readMapBegin();
+              mapEsc = new java.util.HashMap<java.lang.String,Value>(2*_map14.size);
+              @org.apache.thrift.annotation.Nullable java.lang.String _key15;
+              @org.apache.thrift.annotation.Nullable Value _val16;
+              for (int _i17 = 0; _i17 < _map14.size; ++_i17)
+              {
+                _key15 = iprot.readString();
+                _val16 = new Value();
+                _val16.read(iprot);
+                mapEsc.put(_key15, _val16);
+              }
+              iprot.readMapEnd();
+            }
+            return mapEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case SET_ESC:
+          if (field.type == SET_ESC_FIELD_DESC.type) {
+            java.util.Set<Value> setEsc;
+            {
+              org.apache.thrift.protocol.TSet _set18 = iprot.readSetBegin();
+              setEsc = new java.util.HashSet<Value>(2*_set18.size);
+              @org.apache.thrift.annotation.Nullable Value _elem19;
+              for (int _i20 = 0; _i20 < _set18.size; ++_i20)
+              {
+                _elem19 = new Value();
+                _elem19.read(iprot);
+                setEsc.add(_elem19);
+              }
+              iprot.readSetEnd();
+            }
+            return setEsc;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        case SERIALIZED:
+          if (field.type == SERIALIZED_FIELD_DESC.type) {
+            java.lang.String serialized;
+            serialized = iprot.readString();
+            return serialized;
+          } else {
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+            return null;
+          }
+        default:
+          throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!");
+      }
+    } else {
+      org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+      return null;
+    }
+  }
+
+  @Override
+  protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    switch (setField_) {
+      case ATOMIC:
+        AtomicValue atomic = (AtomicValue)value_;
+        atomic.write(oprot);
+        return;
+      case LIST_ESC:
+        java.util.List<Value> listEsc = (java.util.List<Value>)value_;
+        {
+          oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, listEsc.size()));
+          for (Value _iter21 : listEsc)
+          {
+            _iter21.write(oprot);
+          }
+          oprot.writeListEnd();
+        }
+        return;
+      case ARRAY:
+        java.util.List<Value> array = (java.util.List<Value>)value_;
+        {
+          oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, array.size()));
+          for (Value _iter22 : array)
+          {
+            _iter22.write(oprot);
+          }
+          oprot.writeListEnd();
+        }
+        return;
+      case MAP_ESC:
+        java.util.Map<java.lang.String,Value> mapEsc = (java.util.Map<java.lang.String,Value>)value_;
+        {
+          oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, mapEsc.size()));
+          for (java.util.Map.Entry<java.lang.String, Value> _iter23 : mapEsc.entrySet())
+          {
+            oprot.writeString(_iter23.getKey());
+            _iter23.getValue().write(oprot);
+          }
+          oprot.writeMapEnd();
+        }
+        return;
+      case SET_ESC:
+        java.util.Set<Value> setEsc = (java.util.Set<Value>)value_;
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, setEsc.size()));
+          for (Value _iter24 : setEsc)
+          {
+            _iter24.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        return;
+      case SERIALIZED:
+        java.lang.String serialized = (java.lang.String)value_;
+        oprot.writeString(serialized);
+        return;
+      default:
+        throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_);
+    }
+  }
+
+  @Override
+  protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, short fieldID) throws org.apache.thrift.TException {
+    _Fields setField = _Fields.findByThriftId(fieldID);
+    if (setField != null) {
+      switch (setField) {
+        case ATOMIC:
+          AtomicValue atomic;
+          atomic = new AtomicValue();
+          atomic.read(iprot);
+          return atomic;
+        case LIST_ESC:
+          java.util.List<Value> listEsc;
+          {
+            org.apache.thrift.protocol.TList _list25 = iprot.readListBegin();
+            listEsc = new java.util.ArrayList<Value>(_list25.size);
+            @org.apache.thrift.annotation.Nullable Value _elem26;
+            for (int _i27 = 0; _i27 < _list25.size; ++_i27)
+            {
+              _elem26 = new Value();
+              _elem26.read(iprot);
+              listEsc.add(_elem26);
+            }
+            iprot.readListEnd();
+          }
+          return listEsc;
+        case ARRAY:
+          java.util.List<Value> array;
+          {
+            org.apache.thrift.protocol.TList _list28 = iprot.readListBegin();
+            array = new java.util.ArrayList<Value>(_list28.size);
+            @org.apache.thrift.annotation.Nullable Value _elem29;
+            for (int _i30 = 0; _i30 < _list28.size; ++_i30)
+            {
+              _elem29 = new Value();
+              _elem29.read(iprot);
+              array.add(_elem29);
+            }
+            iprot.readListEnd();
+          }
+          return array;
+        case MAP_ESC:
+          java.util.Map<java.lang.String,Value> mapEsc;
+          {
+            org.apache.thrift.protocol.TMap _map31 = iprot.readMapBegin();
+            mapEsc = new java.util.HashMap<java.lang.String,Value>(2*_map31.size);
+            @org.apache.thrift.annotation.Nullable java.lang.String _key32;
+            @org.apache.thrift.annotation.Nullable Value _val33;
+            for (int _i34 = 0; _i34 < _map31.size; ++_i34)
+            {
+              _key32 = iprot.readString();
+              _val33 = new Value();
+              _val33.read(iprot);
+              mapEsc.put(_key32, _val33);
+            }
+            iprot.readMapEnd();
+          }
+          return mapEsc;
+        case SET_ESC:
+          java.util.Set<Value> setEsc;
+          {
+            org.apache.thrift.protocol.TSet _set35 = iprot.readSetBegin();
+            setEsc = new java.util.HashSet<Value>(2*_set35.size);
+            @org.apache.thrift.annotation.Nullable Value _elem36;
+            for (int _i37 = 0; _i37 < _set35.size; ++_i37)
+            {
+              _elem36 = new Value();
+              _elem36.read(iprot);
+              setEsc.add(_elem36);
+            }
+            iprot.readSetEnd();
+          }
+          return setEsc;
+        case SERIALIZED:
+          java.lang.String serialized;
+          serialized = iprot.readString();
+          return serialized;
+        default:
+          throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!");
+      }
+    } else {
+      throw new org.apache.thrift.protocol.TProtocolException("Couldn't find a field with field id " + fieldID);
+    }
+  }
+
+  @Override
+  protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    switch (setField_) {
+      case ATOMIC:
+        AtomicValue atomic = (AtomicValue)value_;
+        atomic.write(oprot);
+        return;
+      case LIST_ESC:
+        java.util.List<Value> listEsc = (java.util.List<Value>)value_;
+        {
+          oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, listEsc.size()));
+          for (Value _iter38 : listEsc)
+          {
+            _iter38.write(oprot);
+          }
+          oprot.writeListEnd();
+        }
+        return;
+      case ARRAY:
+        java.util.List<Value> array = (java.util.List<Value>)value_;
+        {
+          oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, array.size()));
+          for (Value _iter39 : array)
+          {
+            _iter39.write(oprot);
+          }
+          oprot.writeListEnd();
+        }
+        return;
+      case MAP_ESC:
+        java.util.Map<java.lang.String,Value> mapEsc = (java.util.Map<java.lang.String,Value>)value_;
+        {
+          oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, mapEsc.size()));
+          for (java.util.Map.Entry<java.lang.String, Value> _iter40 : mapEsc.entrySet())
+          {
+            oprot.writeString(_iter40.getKey());
+            _iter40.getValue().write(oprot);
+          }
+          oprot.writeMapEnd();
+        }
+        return;
+      case SET_ESC:
+        java.util.Set<Value> setEsc = (java.util.Set<Value>)value_;
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, setEsc.size()));
+          for (Value _iter41 : setEsc)
+          {
+            _iter41.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        return;
+      case SERIALIZED:
+        java.lang.String serialized = (java.lang.String)value_;
+        oprot.writeString(serialized);
+        return;
+      default:
+        throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_);
+    }
+  }
+
+  @Override
+  protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {
+    switch (setField) {
+      case ATOMIC:
+        return ATOMIC_FIELD_DESC;
+      case LIST_ESC:
+        return LIST_ESC_FIELD_DESC;
+      case ARRAY:
+        return ARRAY_FIELD_DESC;
+      case MAP_ESC:
+        return MAP_ESC_FIELD_DESC;
+      case SET_ESC:
+        return SET_ESC_FIELD_DESC;
+      case SERIALIZED:
+        return SERIALIZED_FIELD_DESC;
+      default:
+        throw new java.lang.IllegalArgumentException("Unknown field id " + setField);
+    }
+  }
+
+  @Override
+  protected org.apache.thrift.protocol.TStruct getStructDesc() {
+    return STRUCT_DESC;
+  }
+
+  @Override
+  protected _Fields enumForId(short id) {
+    return _Fields.findByThriftIdOrThrow(id);
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+
+  /**
+   * An atomic (simple) value
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+   */
+  public AtomicValue getAtomic() {
+    if (getSetField() == _Fields.ATOMIC) {
+      return (AtomicValue)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'atomic' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * An atomic (simple) value
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+   */
+  public void setAtomic(AtomicValue value) {
+    setField_ = _Fields.ATOMIC;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.ATOMIC");
+  }
+
+  /**
+   * An ordered list value
+   * 
+   * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public java.util.List<Value> getListEsc() {
+    if (getSetField() == _Fields.LIST_ESC) {
+      return (java.util.List<Value>)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'listEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * An ordered list value
+   * 
+   * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public void setListEsc(java.util.List<Value> value) {
+    setField_ = _Fields.LIST_ESC;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.LIST_ESC");
+  }
+
+  /**
+   * An array value. Like a list, but also supporting efficient random access
+   * 
+   * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public java.util.List<Value> getArray() {
+    if (getSetField() == _Fields.ARRAY) {
+      return (java.util.List<Value>)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'array' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * An array value. Like a list, but also supporting efficient random access
+   * 
+   * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public void setArray(java.util.List<Value> value) {
+    setField_ = _Fields.ARRAY;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.ARRAY");
+  }
+
+  /**
+   * A map of arbitrary string keys to arbitrary values
+   * 
+   * @type map:
+   *         keys: string
+   *         values: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public java.util.Map<java.lang.String,Value> getMapEsc() {
+    if (getSetField() == _Fields.MAP_ESC) {
+      return (java.util.Map<java.lang.String,Value>)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'mapEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A map of arbitrary string keys to arbitrary values
+   * 
+   * @type map:
+   *         keys: string
+   *         values: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public void setMapEsc(java.util.Map<java.lang.String,Value> value) {
+    setField_ = _Fields.MAP_ESC;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.MAP_ESC");
+  }
+
+  /**
+   * A set of unique values
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public java.util.Set<Value> getSetEsc() {
+    if (getSetField() == _Fields.SET_ESC) {
+      return (java.util.Set<Value>)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'setEsc' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A set of unique values
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+   */
+  public void setSetEsc(java.util.Set<Value> value) {
+    setField_ = _Fields.SET_ESC;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.SET_ESC");
+  }
+
+  /**
+   * A serialized object which the application should be capable of decoding
+   * 
+   * @type string
+   */
+  public java.lang.String getSerialized() {
+    if (getSetField() == _Fields.SERIALIZED) {
+      return (java.lang.String)getFieldValue();
+    } else {
+      throw new java.lang.RuntimeException("Cannot get field 'serialized' because union is currently set to " + getFieldDesc(getSetField()).name);
+    }
+  }
+
+  /**
+   * A serialized object which the application should be capable of decoding
+   * 
+   * @type string
+   */
+  public void setSerialized(java.lang.String value) {
+    setField_ = _Fields.SERIALIZED;
+    value_ = java.util.Objects.requireNonNull(value,"_Fields.SERIALIZED");
+  }
+
+  public boolean isSetAtomic() {
+    return setField_ == _Fields.ATOMIC;
+  }
+
+
+  public boolean isSetListEsc() {
+    return setField_ == _Fields.LIST_ESC;
+  }
+
+
+  public boolean isSetArray() {
+    return setField_ == _Fields.ARRAY;
+  }
+
+
+  public boolean isSetMapEsc() {
+    return setField_ == _Fields.MAP_ESC;
+  }
+
+
+  public boolean isSetSetEsc() {
+    return setField_ == _Fields.SET_ESC;
+  }
+
+
+  public boolean isSetSerialized() {
+    return setField_ == _Fields.SERIALIZED;
+  }
+
+
+  public boolean equals(java.lang.Object other) {
+    if (other instanceof Value) {
+      return equals((Value)other);
+    } else {
+      return false;
+    }
+  }
+
+  public boolean equals(Value other) {
+    return other != null && getSetField() == other.getSetField() && getFieldValue().equals(other.getFieldValue());
+  }
+
+  @Override
+  public int compareTo(Value other) {
+    int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), other.getSetField());
+    if (lastComparison == 0) {
+      return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());
+    }
+    return lastComparison;
+  }
+
+
+  @Override
+  public int hashCode() {
+    java.util.List<java.lang.Object> list = new java.util.ArrayList<java.lang.Object>();
+    list.add(this.getClass().getName());
+    org.apache.thrift.TFieldIdEnum setField = getSetField();
+    if (setField != null) {
+      list.add(setField.getThriftFieldId());
+      java.lang.Object value = getFieldValue();
+      if (value instanceof org.apache.thrift.TEnum) {
+        list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());
+      } else {
+        list.add(value);
+      }
+    }
+    return list.hashCode();
+  }
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Vertex.java b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Vertex.java
new file mode 100644
index 0000000..3a6f8fc
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/java/org/apache/tinkerpop/gremlin/language/property_graphs/Vertex.java
@@ -0,0 +1,704 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.tinkerpop.gremlin.language.property_graphs;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A vertex, or simple element in a graph; vertices are typically connected by edges
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-06")
+public class Vertex implements org.apache.thrift.TBase<Vertex, Vertex._Fields>, java.io.Serializable, Cloneable, Comparable<Vertex> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Vertex");
+
+  private static final org.apache.thrift.protocol.TField ID_FIELD_DESC = new org.apache.thrift.protocol.TField("id", org.apache.thrift.protocol.TType.STRUCT, (short)1);
+  private static final org.apache.thrift.protocol.TField LABEL_FIELD_DESC = new org.apache.thrift.protocol.TField("label", org.apache.thrift.protocol.TType.STRING, (short)2);
+  private static final org.apache.thrift.protocol.TField PROPERTIES_FIELD_DESC = new org.apache.thrift.protocol.TField("properties", org.apache.thrift.protocol.TType.SET, (short)3);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new VertexStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new VertexTupleSchemeFactory();
+
+  /**
+   * The unique id of the vertex; no two vertices in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   * @unique true
+   */
+  public @org.apache.thrift.annotation.Nullable AtomicValue id; // required
+  /**
+   * The optional label of the vertex, sometimes indicating its type
+   * 
+   * @type optional: org/apache/tinkerpop/gremlin/language/property_graphs.VertexLabel
+   */
+  public @org.apache.thrift.annotation.Nullable java.lang.String label; // optional
+  /**
+   * Any properties (key/value pairs) of the vertex
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public @org.apache.thrift.annotation.Nullable java.util.Set<Property> properties; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    /**
+     * The unique id of the vertex; no two vertices in a graph may share the same id
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     * @unique true
+     */
+    ID((short)1, "id"),
+    /**
+     * The optional label of the vertex, sometimes indicating its type
+     * 
+     * @type optional: org/apache/tinkerpop/gremlin/language/property_graphs.VertexLabel
+     */
+    LABEL((short)2, "label"),
+    /**
+     * Any properties (key/value pairs) of the vertex
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    PROPERTIES((short)3, "properties");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // ID
+          return ID;
+        case 2: // LABEL
+          return LABEL;
+        case 3: // PROPERTIES
+          return PROPERTIES;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  private static final _Fields optionals[] = {_Fields.LABEL};
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.ID, new org.apache.thrift.meta_data.FieldMetaData("id", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT        , "VertexId")));
+    tmpMap.put(_Fields.LABEL, new org.apache.thrift.meta_data.FieldMetaData("label", org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , "VertexLabel")));
+    tmpMap.put(_Fields.PROPERTIES, new org.apache.thrift.meta_data.FieldMetaData("properties", org.apache.thrift.TFieldRequirementType.REQUIRED, 
+        new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, 
+            new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Property.class))));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Vertex.class, metaDataMap);
+  }
+
+  public Vertex() {
+  }
+
+  public Vertex(
+    AtomicValue id,
+    java.util.Set<Property> properties)
+  {
+    this();
+    this.id = id;
+    this.properties = properties;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public Vertex(Vertex other) {
+    if (other.isSetId()) {
+      this.id = new AtomicValue(other.id);
+    }
+    if (other.isSetLabel()) {
+      this.label = other.label;
+    }
+    if (other.isSetProperties()) {
+      java.util.Set<Property> __this__properties = new java.util.HashSet<Property>(other.properties.size());
+      for (Property other_element : other.properties) {
+        __this__properties.add(new Property(other_element));
+      }
+      this.properties = __this__properties;
+    }
+  }
+
+  public Vertex deepCopy() {
+    return new Vertex(this);
+  }
+
+  @Override
+  public void clear() {
+    this.id = null;
+    this.label = null;
+    this.properties = null;
+  }
+
+  /**
+   * The unique id of the vertex; no two vertices in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   * @unique true
+   */
+  @org.apache.thrift.annotation.Nullable
+  public AtomicValue getId() {
+    return this.id;
+  }
+
+  /**
+   * The unique id of the vertex; no two vertices in a graph may share the same id
+   * 
+   * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+   * @unique true
+   */
+  public Vertex setId(@org.apache.thrift.annotation.Nullable AtomicValue id) {
+    this.id = id;
+    return this;
+  }
+
+  public void unsetId() {
+    this.id = null;
+  }
+
+  /** Returns true if field id is set (has been assigned a value) and false otherwise */
+  public boolean isSetId() {
+    return this.id != null;
+  }
+
+  public void setIdIsSet(boolean value) {
+    if (!value) {
+      this.id = null;
+    }
+  }
+
+  /**
+   * The optional label of the vertex, sometimes indicating its type
+   * 
+   * @type optional: org/apache/tinkerpop/gremlin/language/property_graphs.VertexLabel
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getLabel() {
+    return this.label;
+  }
+
+  /**
+   * The optional label of the vertex, sometimes indicating its type
+   * 
+   * @type optional: org/apache/tinkerpop/gremlin/language/property_graphs.VertexLabel
+   */
+  public Vertex setLabel(@org.apache.thrift.annotation.Nullable java.lang.String label) {
+    this.label = label;
+    return this;
+  }
+
+  public void unsetLabel() {
+    this.label = null;
+  }
+
+  /** Returns true if field label is set (has been assigned a value) and false otherwise */
+  public boolean isSetLabel() {
+    return this.label != null;
+  }
+
+  public void setLabelIsSet(boolean value) {
+    if (!value) {
+      this.label = null;
+    }
+  }
+
+  public int getPropertiesSize() {
+    return (this.properties == null) ? 0 : this.properties.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Property> getPropertiesIterator() {
+    return (this.properties == null) ? null : this.properties.iterator();
+  }
+
+  public void addToProperties(Property elem) {
+    if (this.properties == null) {
+      this.properties = new java.util.HashSet<Property>();
+    }
+    this.properties.add(elem);
+  }
+
+  /**
+   * Any properties (key/value pairs) of the vertex
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Set<Property> getProperties() {
+    return this.properties;
+  }
+
+  /**
+   * Any properties (key/value pairs) of the vertex
+   * 
+   * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+   */
+  public Vertex setProperties(@org.apache.thrift.annotation.Nullable java.util.Set<Property> properties) {
+    this.properties = properties;
+    return this;
+  }
+
+  public void unsetProperties() {
+    this.properties = null;
+  }
+
+  /** Returns true if field properties is set (has been assigned a value) and false otherwise */
+  public boolean isSetProperties() {
+    return this.properties != null;
+  }
+
+  public void setPropertiesIsSet(boolean value) {
+    if (!value) {
+      this.properties = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case ID:
+      if (value == null) {
+        unsetId();
+      } else {
+        setId((AtomicValue)value);
+      }
+      break;
+
+    case LABEL:
+      if (value == null) {
+        unsetLabel();
+      } else {
+        setLabel((java.lang.String)value);
+      }
+      break;
+
+    case PROPERTIES:
+      if (value == null) {
+        unsetProperties();
+      } else {
+        setProperties((java.util.Set<Property>)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case ID:
+      return getId();
+
+    case LABEL:
+      return getLabel();
+
+    case PROPERTIES:
+      return getProperties();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case ID:
+      return isSetId();
+    case LABEL:
+      return isSetLabel();
+    case PROPERTIES:
+      return isSetProperties();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof Vertex)
+      return this.equals((Vertex)that);
+    return false;
+  }
+
+  public boolean equals(Vertex that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_id = true && this.isSetId();
+    boolean that_present_id = true && that.isSetId();
+    if (this_present_id || that_present_id) {
+      if (!(this_present_id && that_present_id))
+        return false;
+      if (!this.id.equals(that.id))
+        return false;
+    }
+
+    boolean this_present_label = true && this.isSetLabel();
+    boolean that_present_label = true && that.isSetLabel();
+    if (this_present_label || that_present_label) {
+      if (!(this_present_label && that_present_label))
+        return false;
+      if (!this.label.equals(that.label))
+        return false;
+    }
+
+    boolean this_present_properties = true && this.isSetProperties();
+    boolean that_present_properties = true && that.isSetProperties();
+    if (this_present_properties || that_present_properties) {
+      if (!(this_present_properties && that_present_properties))
+        return false;
+      if (!this.properties.equals(that.properties))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetId()) ? 131071 : 524287);
+    if (isSetId())
+      hashCode = hashCode * 8191 + id.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetLabel()) ? 131071 : 524287);
+    if (isSetLabel())
+      hashCode = hashCode * 8191 + label.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetProperties()) ? 131071 : 524287);
+    if (isSetProperties())
+      hashCode = hashCode * 8191 + properties.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(Vertex other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetId(), other.isSetId());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetId()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.id, other.id);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetLabel(), other.isSetLabel());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetLabel()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.label, other.label);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetProperties(), other.isSetProperties());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetProperties()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.properties, other.properties);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("Vertex(");
+    boolean first = true;
+
+    sb.append("id:");
+    if (this.id == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.id);
+    }
+    first = false;
+    if (isSetLabel()) {
+      if (!first) sb.append(", ");
+      sb.append("label:");
+      if (this.label == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.label);
+      }
+      first = false;
+    }
+    if (!first) sb.append(", ");
+    sb.append("properties:");
+    if (this.properties == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.properties);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    if (id == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'id' was not present! Struct: " + toString());
+    }
+    if (properties == null) {
+      throw new org.apache.thrift.protocol.TProtocolException("Required field 'properties' was not present! Struct: " + toString());
+    }
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class VertexStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public VertexStandardScheme getScheme() {
+      return new VertexStandardScheme();
+    }
+  }
+
+  private static class VertexStandardScheme extends org.apache.thrift.scheme.StandardScheme<Vertex> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, Vertex struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // ID
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+              struct.id = new AtomicValue();
+              struct.id.read(iprot);
+              struct.setIdIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // LABEL
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.label = iprot.readString();
+              struct.setLabelIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 3: // PROPERTIES
+            if (schemeField.type == org.apache.thrift.protocol.TType.SET) {
+              {
+                org.apache.thrift.protocol.TSet _set50 = iprot.readSetBegin();
+                struct.properties = new java.util.HashSet<Property>(2*_set50.size);
+                @org.apache.thrift.annotation.Nullable Property _elem51;
+                for (int _i52 = 0; _i52 < _set50.size; ++_i52)
+                {
+                  _elem51 = new Property();
+                  _elem51.read(iprot);
+                  struct.properties.add(_elem51);
+                }
+                iprot.readSetEnd();
+              }
+              struct.setPropertiesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, Vertex struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.id != null) {
+        oprot.writeFieldBegin(ID_FIELD_DESC);
+        struct.id.write(oprot);
+        oprot.writeFieldEnd();
+      }
+      if (struct.label != null) {
+        if (struct.isSetLabel()) {
+          oprot.writeFieldBegin(LABEL_FIELD_DESC);
+          oprot.writeString(struct.label);
+          oprot.writeFieldEnd();
+        }
+      }
+      if (struct.properties != null) {
+        oprot.writeFieldBegin(PROPERTIES_FIELD_DESC);
+        {
+          oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(org.apache.thrift.protocol.TType.STRUCT, struct.properties.size()));
+          for (Property _iter53 : struct.properties)
+          {
+            _iter53.write(oprot);
+          }
+          oprot.writeSetEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class VertexTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public VertexTupleScheme getScheme() {
+      return new VertexTupleScheme();
+    }
+  }
+
+  private static class VertexTupleScheme extends org.apache.thrift.scheme.TupleScheme<Vertex> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, Vertex struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      struct.id.write(oprot);
+      {
+        oprot.writeI32(struct.properties.size());
+        for (Property _iter54 : struct.properties)
+        {
+          _iter54.write(oprot);
+        }
+      }
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetLabel()) {
+        optionals.set(0);
+      }
+      oprot.writeBitSet(optionals, 1);
+      if (struct.isSetLabel()) {
+        oprot.writeString(struct.label);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, Vertex struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      struct.id = new AtomicValue();
+      struct.id.read(iprot);
+      struct.setIdIsSet(true);
+      {
+        org.apache.thrift.protocol.TSet _set55 = iprot.readSetBegin(org.apache.thrift.protocol.TType.STRUCT);
+        struct.properties = new java.util.HashSet<Property>(2*_set55.size);
+        @org.apache.thrift.annotation.Nullable Property _elem56;
+        for (int _i57 = 0; _i57 < _set55.size; ++_i57)
+        {
+          _elem56 = new Property();
+          _elem56.read(iprot);
+          struct.properties.add(_elem56);
+        }
+      }
+      struct.setPropertiesIsSet(true);
+      java.util.BitSet incoming = iprot.readBitSet(1);
+      if (incoming.get(0)) {
+        struct.label = iprot.readString();
+        struct.setLabelIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/gremlin-language/examples/graphs-over-thrift/src/gen/thrift/org/apache/tinkerpop/gremlin/language/property_graphs.thrift b/gremlin-language/examples/graphs-over-thrift/src/gen/thrift/org/apache/tinkerpop/gremlin/language/property_graphs.thrift
new file mode 100644
index 0000000..820db6c
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/gen/thrift/org/apache/tinkerpop/gremlin/language/property_graphs.thrift
@@ -0,0 +1,248 @@
+/**
+ * Basic Property Graph data model
+ * 
+ * @name org/apache/tinkerpop/gremlin/language/property_graphs
+ * @note This is an auto-generated file. Manual changes to the file may not be preserved.
+ * @status development
+ */
+
+namespace java org.apache.tinkerpop.gremlin.language.property_graphs
+
+/**
+ * The label of an edge, sometimes indicating its type
+ * 
+ * @type string
+ */
+typedef string EdgeLabel
+
+/**
+ * The key of a property. Property keys are part of a graph's schema, like vertex and edge labels.
+ * 
+ * @type string
+ */
+typedef string PropertyKey
+
+/**
+ * The label of a vertex, sometimes indicating its type
+ * 
+ * @type string
+ */
+typedef string VertexLabel
+
+/**
+ * A simple value like a boolean, number, or string
+ */
+union AtomicValue {
+    /**
+     * A boolean (true/false) value
+     * 
+     * @type boolean
+     */
+    1: optional bool booleanEsc;
+    /**
+     * A byte (8-bit integer) value
+     * 
+     * @type integer:
+     *         precision:
+     *           bits: 8
+     */
+    2: optional i16 byteEsc;
+    /**
+     * A double-precision (64-bit) floating point value
+     * 
+     * @type float:
+     *         precision:
+     *           bits: 64
+     */
+    3: optional double doubleEsc;
+    /**
+     * A single-precision (32-bit) floating point value
+     * 
+     * @type float
+     */
+    4: optional double floatEsc;
+    /**
+     * A 32-bit integer value
+     * 
+     * @type integer
+     */
+    5: optional i32 integer;
+    /**
+     * A 64-bit integer value
+     * 
+     * @type integer:
+     *         precision:
+     *           bits: 64
+     */
+    6: optional i64 longEsc;
+    /**
+     * A string value
+     * 
+     * @type string
+     */
+    7: optional string stringEsc;
+}
+
+/**
+ * The unique id of an edge
+ * 
+ * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+ */
+typedef AtomicValue EdgeId
+
+/**
+ * A property, or key/value pair which may be attached to vertices, edges, and occasionally other properties.
+ */
+struct Property {
+    /**
+     * The property's key
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.PropertyKey
+     */
+    1: required PropertyKey key;
+    /**
+     * The property's value
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    2: required Value value;
+    /**
+     * Any metaproperties (properties of a property)
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    3: required set<Property> metaproperties;
+}
+
+/**
+ * An id or property value; either an atomic (simple) value, or a list, map, or set value
+ */
+union Value {
+    /**
+     * An atomic (simple) value
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+     */
+    1: optional AtomicValue atomic;
+    /**
+     * An ordered list value
+     * 
+     * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    2: optional list<Value> listEsc;
+    /**
+     * An array value. Like a list, but also supporting efficient random access
+     * 
+     * @type list: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    3: optional list<Value> array;
+    /**
+     * A map of arbitrary string keys to arbitrary values
+     * 
+     * @type map:
+     *         keys: string
+     *         values: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    4: optional map<string, Value> mapEsc;
+    /**
+     * A set of unique values
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Value
+     */
+    5: optional set<Value> setEsc;
+    /**
+     * A serialized object which the application should be capable of decoding
+     * 
+     * @type string
+     */
+    6: optional string serialized;
+}
+
+/**
+ * The unique id of a vertex
+ * 
+ * @type org/apache/tinkerpop/gremlin/language/property_graphs.AtomicValue
+ */
+typedef AtomicValue VertexId
+
+/**
+ * A edge, or binary relationship connecting two vertices
+ */
+struct Edge {
+    /**
+     * The unique id of the edge; no two edges in a graph may share the same id
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeId
+     * @unique true
+     */
+    1: required EdgeId id;
+    /**
+     * The label of the edge, sometimes indicating its type
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.EdgeLabel
+     */
+    2: required EdgeLabel label;
+    /**
+     * Any properties (key/value pairs) of the edge
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    3: required set<Property> properties;
+    /**
+     * The id of the edge's out-vertex (tail)
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     */
+    4: required VertexId outVertexId;
+    /**
+     * The id if the edge's in-vertex (head)
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     */
+    5: required VertexId inVertexId;
+}
+
+/**
+ * A vertex, or simple element in a graph; vertices are typically connected by edges
+ */
+struct Vertex {
+    /**
+     * The unique id of the vertex; no two vertices in a graph may share the same id
+     * 
+     * @type org/apache/tinkerpop/gremlin/language/property_graphs.VertexId
+     * @unique true
+     */
+    1: required VertexId id;
+    /**
+     * The optional label of the vertex, sometimes indicating its type
+     * 
+     * @type optional: org/apache/tinkerpop/gremlin/language/property_graphs.VertexLabel
+     */
+    2: optional VertexLabel label;
+    /**
+     * Any properties (key/value pairs) of the vertex
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Property
+     */
+    3: required set<Property> properties;
+}
+
+/**
+ * A graph, consisting of a set of vertices and a set of edges
+ * 
+ * @comments As a basic integrity constraint, the out- and in- vertex ids of the graph's edges must be among the ids of the graph's vertices.
+ */
+struct Graph {
+    /**
+     * The set of all vertices in the graph
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Vertex
+     */
+    1: required set<Vertex> vertices;
+    /**
+     * The set of all edges in the graph
+     * 
+     * @type set: org/apache/tinkerpop/gremlin/language/property_graphs.Edge
+     */
+    2: required set<Edge> edges;
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphHandler.java b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphHandler.java
new file mode 100644
index 0000000..15383bf
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/AddGraphHandler.java
@@ -0,0 +1,83 @@
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+import org.apache.commons.configuration2.BaseConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.thrift.TException;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AddGraphHandler implements ExampleService.Iface {
+
+    @Override
+    public AddGraphResponse addGraph(org.apache.tinkerpop.gremlin.language.property_graphs.Graph g0)
+            throws AddGraphException, TException {
+        Configuration conf = new BaseConfiguration();
+        conf.setProperty("gremlin.tinkergraph.graphLocation", "/tmp/graphs-over-thrift.json");
+        conf.setProperty("gremlin.tinkergraph.graphFormat", "graphson");
+        //conf.setProperty("gremlin.tinkergraph.graphLocation", "/tmp/graphs-over-thrift.xml");
+        //conf.setProperty("gremlin.tinkergraph.graphFormat", "graphml");
+        Graph graph;
+
+        try {
+            graph = TinkerGraph.open(conf);
+        } catch (Exception e) {
+            throw new AddGraphException("could not open graph: " + e.getMessage());
+        }
+
+        // Add vertices
+        Map<Object, Vertex> vertices = new HashMap<>();
+        for (org.apache.tinkerpop.gremlin.language.property_graphs.Vertex v0 : g0.vertices) {
+            Object id = GraphThriftUtils.toNativeAtomicValue(v0.id);
+            Vertex v = graph.addVertex(T.id, id);
+            for (org.apache.tinkerpop.gremlin.language.property_graphs.Property p0 : v0.properties) {
+                v.property(p0.key, GraphThriftUtils.toNativeValue(p0.value));
+            }
+
+            vertices.put(id, v);
+        }
+
+        // Add edges
+        for (org.apache.tinkerpop.gremlin.language.property_graphs.Edge e0 : g0.edges) {
+            Object id = GraphThriftUtils.toNativeAtomicValue(e0.id);
+            Object outId = GraphThriftUtils.toNativeAtomicValue(e0.outVertexId);
+            Object inId = GraphThriftUtils.toNativeAtomicValue(e0.inVertexId);
+
+            Vertex out = vertices.get(outId);
+            Vertex in = vertices.get(inId);
+            if (out == null || in == null) {
+                throw new AddGraphException("edge references vertices which are not in the graph");
+            }
+
+            Edge e = out.addEdge(e0.label, in, T.id, id);
+
+            for (org.apache.tinkerpop.gremlin.language.property_graphs.Property p0 : e0.properties) {
+                e.property(p0.key, GraphThriftUtils.toNativeValue(p0.value));
+                //System.out.println("Thrift value: " + p0.value + ", native value: " + GraphThriftUtils.toNativeValue(p0.value));
+            }
+        }
+
+        GraphTraversalSource g = graph.traversal();
+        long vertexCount = g.V().count().next();
+        long edgeCount = g.E().count().next();
+
+        try {
+            // This should cause the graph to be saved to the configured location
+            graph.close();
+        } catch (Exception e) {
+            throw new AddGraphException("failed to close graph: " + e.getMessage());
+        }
+
+        AddGraphResponse response = new AddGraphResponse();
+        response.setTotalVerticesAfterOperation(vertexCount);
+        response.setTotalEdgesAfterOperation(edgeCount);
+
+        return response;
+    }
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphClient.java b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphClient.java
new file mode 100644
index 0000000..0fdbf8a
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphClient.java
@@ -0,0 +1,41 @@
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+
+public class ExampleGraphClient {
+
+    public static void main(String[] args) {
+        try {
+            TTransport transport;
+
+            transport = new TSocket("localhost", 9090);
+            transport.open();
+
+            TProtocol protocol = new TBinaryProtocol(transport);
+            ExampleService.Client client = new ExampleService.Client(protocol);
+
+            perform(client);
+
+            transport.close();
+        } catch (TException x) {
+            x.printStackTrace();
+        }
+    }
+
+    private static void perform(ExampleService.Client client) throws TException {
+        Graph graph = TinkerFactory.createClassic();
+        GraphTraversalSource g = graph.traversal();
+        g.V(4L).next().property("awesomenessLevel", 1.0);
+
+        AddGraphResponse response = client.addGraph(GraphThriftUtils.fromNativeGraph(graph));
+        System.out.println("resulting graph has " + response.totalVerticesAfterOperation + " vertices and "
+            + response.totalEdgesAfterOperation + " edges.");
+    }
+}
\ No newline at end of file
diff --git a/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphServer.java b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphServer.java
new file mode 100644
index 0000000..704afb7
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/ExampleGraphServer.java
@@ -0,0 +1,38 @@
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TSimpleServer;
+import org.apache.thrift.transport.TServerSocket;
+import org.apache.thrift.transport.TServerTransport;
+
+public class ExampleGraphServer {
+
+    public static AddGraphHandler handler;
+
+    public static ExampleService.Processor processor;
+
+    public static void main(String[] args) {
+        try {
+            handler = new AddGraphHandler();
+            processor = new ExampleService.Processor(handler);
+
+            Runnable simple = () -> simple(processor);
+
+            new Thread(simple).start();
+        } catch (Exception x) {
+            x.printStackTrace();
+        }
+    }
+
+    public static void simple(ExampleService.Processor processor) {
+        try {
+            TServerTransport serverTransport = new TServerSocket(9090);
+            TServer server = new TSimpleServer(new TServer.Args(serverTransport).processor(processor));
+
+            System.out.println("Starting the graph server...");
+            server.serve();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/GraphThriftUtils.java b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/GraphThriftUtils.java
new file mode 100644
index 0000000..cc04c3b
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/main/java/org/apache/tinkerpop/gremlin/language/examples/thrift/GraphThriftUtils.java
@@ -0,0 +1,190 @@
+package org.apache.tinkerpop.gremlin.language.examples.thrift;
+
+import org.apache.tinkerpop.gremlin.language.property_graphs.AtomicValue;
+import org.apache.tinkerpop.gremlin.language.property_graphs.Value;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class GraphThriftUtils {
+    public static AtomicValue fromNativeAtomicValue(Object o) {
+        if (o instanceof Boolean) {
+            return AtomicValue.booleanEsc((Boolean) o);
+        } else if (o instanceof Short) {
+            return AtomicValue.byteEsc((Short) o);
+        } else if (o instanceof Double) {
+            return AtomicValue.doubleEsc((Double) o);
+        } else if (o instanceof Float) {
+            // Note: toString avoids float-to-double precision issues
+            return AtomicValue.floatEsc(Double.parseDouble(o.toString()));
+        } else if (o instanceof Integer) {
+            return AtomicValue.integer((Integer) o);
+        } else if (o instanceof Long) {
+            return AtomicValue.longEsc((Long) o);
+        } else if (o instanceof String) {
+            return AtomicValue.stringEsc((String) o);
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    public static org.apache.tinkerpop.gremlin.language.property_graphs.Graph fromNativeGraph(Graph graph) {
+        Set<org.apache.tinkerpop.gremlin.language.property_graphs.Vertex> vertices0 = new HashSet<>();
+        Iterator<Vertex> vertices = graph.vertices();
+        while (vertices.hasNext()) {
+            Vertex v = vertices.next();
+
+            org.apache.tinkerpop.gremlin.language.property_graphs.Vertex v0
+                    = new org.apache.tinkerpop.gremlin.language.property_graphs.Vertex();
+            v0.setId(fromNativeAtomicValue(v.id()));
+            v0.setLabel(v.label());
+
+            Iterator<VertexProperty<Object>> props = v.properties();
+            Set<org.apache.tinkerpop.gremlin.language.property_graphs.Property> props0 = new HashSet<>();
+            while (props.hasNext()) {
+                props0.add(fromNativeProperty(props.next()));
+            }
+            v0.setProperties(props0);
+
+            vertices0.add(v0);
+        }
+
+        Set<org.apache.tinkerpop.gremlin.language.property_graphs.Edge> edges0 = new HashSet<>();
+        Iterator<Edge> edges = graph.edges();
+        while (edges.hasNext()) {
+            Edge e = edges.next();
+
+            org.apache.tinkerpop.gremlin.language.property_graphs.Edge e0
+                    = new org.apache.tinkerpop.gremlin.language.property_graphs.Edge();
+            e0.setId(fromNativeAtomicValue(e.id()));
+            e0.setLabel(e.label());
+            e0.setOutVertexId(fromNativeAtomicValue(e.outVertex().id()));
+            e0.setInVertexId(fromNativeAtomicValue(e.inVertex().id()));
+
+            Iterator<Property<Object>> props = e.properties();
+            Set<org.apache.tinkerpop.gremlin.language.property_graphs.Property> props0 = new HashSet<>();
+            while (props.hasNext()) {
+                props0.add(fromNativeProperty(props.next()));
+            }
+            e0.setProperties(props0);
+
+            edges0.add(e0);
+        }
+
+        org.apache.tinkerpop.gremlin.language.property_graphs.Graph graph0
+                = new org.apache.tinkerpop.gremlin.language.property_graphs.Graph();
+        graph0.setVertices(vertices0);
+        graph0.setEdges(edges0);
+
+        return graph0;
+    }
+
+    public static org.apache.tinkerpop.gremlin.language.property_graphs.Property fromNativeProperty(Property prop) {
+        org.apache.tinkerpop.gremlin.language.property_graphs.Property p0
+                = new org.apache.tinkerpop.gremlin.language.property_graphs.Property();
+        p0.setKey(prop.key());
+        p0.setValue(fromNativeValue(prop.value()));
+        p0.setMetaproperties(new HashSet<>()); // don't bother with metaproperties for now
+
+        //System.out.println("Native value: " + prop.value() + " ( " + prop.value().getClass() + ")"
+        //        + " --> Thrift value: " + fromNativeValue(prop.value()));
+        return p0;
+    }
+
+    public static Value fromNativeValue(Object o) {
+        if (o.getClass().isArray()) {
+            List<Value> coll = new ArrayList<>();
+            for (Object o1 : (Object[]) o) {
+                coll.add(fromNativeValue(o1));
+            }
+            return Value.array(coll);
+        } else if (o instanceof List) {
+            List<Value> coll = new ArrayList<>();
+            for (Object o1 : (List<Object>) o) {
+                coll.add(fromNativeValue(o1));
+            }
+            return Value.listEsc(coll);
+        } else if (o instanceof Set) {
+            Set<Value> coll = new HashSet<>();
+            for (Object o1 : (Set<Object>) o) {
+                coll.add(fromNativeValue(o1));
+            }
+            return Value.setEsc(coll);
+        } else if (o instanceof Map) {
+            Map<String, Value> coll = new HashMap<>();
+            for (Map.Entry<String, Object> e : ((Map<String, Object>) o).entrySet()) {
+                coll.put(e.getKey(), fromNativeValue(e.getValue()));
+            }
+            return Value.mapEsc(coll);
+        } else {
+            return Value.atomic(fromNativeAtomicValue(o));
+        }
+    }
+
+    public static Object toNativeAtomicValue(AtomicValue v) {
+        if (v.isSetBooleanEsc()) {
+            return v.getBooleanEsc();
+        } else if (v.isSetByteEsc()) {
+            return v.getByteEsc();
+        } else if (v.isSetDoubleEsc()) {
+            return v.getDoubleEsc();
+        } else if (v.isSetFloatEsc()) {
+            return v.getFloatEsc();
+        } else if (v.isSetInteger()) {
+            return v.getInteger();
+        } else if (v.isSetLongEsc()) {
+            return v.getLongEsc();
+        } else if (v.isSetStringEsc()) {
+            return v.getStringEsc();
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    public static Object toNativeValue(Value v) {
+        if (v.isSetAtomic()) {
+            return toNativeAtomicValue(v.getAtomic());
+        } else if (v.isSetListEsc()) {
+            List<Object> coll = new LinkedList<>();
+            for (Value v1 : v.getListEsc()) {
+                coll.add(toNativeValue(v1));
+            }
+            return coll;
+        } else if (v.isSetArray()) {
+            Object[] array = new Object[v.getArray().size()];
+            int i = 0;
+            for (Value v1 : v.getArray()) {
+                array[i++] = toNativeValue(v1);
+            }
+            return array;
+        } else if (v.isSetMapEsc()) {
+            Map<String, Object> map = new HashMap<>();
+            for (Map.Entry<String, Value> e : v.getMapEsc().entrySet()) {
+                map.put(e.getKey(), toNativeValue(e.getValue()));
+            }
+            return map;
+        } else if (v.isSetSetEsc()) {
+            Set<Object> coll = new HashSet<>();
+            for (Value v1 : v.getSetEsc()) {
+                coll.add(toNativeValue(v1));
+            }
+            return coll;
+        } else if (v.isSetSerialized()) {
+            // Note: an appropriate deserializer should be used here
+            return v.getSerialized();
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+}
diff --git a/gremlin-language/examples/graphs-over-thrift/src/main/thrift/graphs_over_thrift.thrift b/gremlin-language/examples/graphs-over-thrift/src/main/thrift/graphs_over_thrift.thrift
new file mode 100644
index 0000000..e8ed1f5
--- /dev/null
+++ b/gremlin-language/examples/graphs-over-thrift/src/main/thrift/graphs_over_thrift.thrift
@@ -0,0 +1,16 @@
+namespace java org.apache.tinkerpop.gremlin.language.examples.thrift
+
+include "../../../src/gen/thrift/org/apache/tinkerpop/gremlin/language/property_graphs.thrift"
+
+exception AddGraphException {
+    1: string message;
+}
+
+struct AddGraphResponse {
+    1: i64 totalVerticesAfterOperation;
+    2: i64 totalEdgesAfterOperation;
+}
+
+service ExampleService {
+    AddGraphResponse addGraph(1: property_graphs.Graph graph) throws (1: AddGraphException error)
+}
diff --git a/gremlin-language/src/main/yaml/org/apache/tinkerpop/gremlin/language/property_graphs.yaml b/gremlin-language/src/main/yaml/org/apache/tinkerpop/gremlin/language/property_graphs.yaml
index 9407ec5..f481ecb 100644
--- a/gremlin-language/src/main/yaml/org/apache/tinkerpop/gremlin/language/property_graphs.yaml
+++ b/gremlin-language/src/main/yaml/org/apache/tinkerpop/gremlin/language/property_graphs.yaml
@@ -97,7 +97,7 @@ definitions:
           type:
             set: Vertex
 
-        - name: edge
+        - name: edges
           description: "The set of all edges in the graph"
           type:
             set: Edge

Re: [tinkerpop] 03/04: Add a runnable example of a Thrift client sending graphs to a server over TChannel

Posted by Joshua Shinavier <jo...@fortytwo.net>.
FYI, I have extended the example to use the Protobuf-like solution for
domain-specific objects which I mentioned above. The overall flow of the
example is this:

   - The client creates and populates a TinkerGraph instance. One of the
   properties has the key "livesIn" and a value which is an instance of a
   domain-specific BoundingBox class.
   - The client encodes the graph to an instance of the Thrift-generated
   Graph class. The BoundingBox is serialized using a JSON-based encoder which
   has been added to an encoder registry that is shared between client and
   server.
   - The Thrift-generated code sends the encoded graph across the wire to
   the server, which receives it again as an instance of the Thrift-generated
   Graph class
   - The server decodes the graph to a new instance of TinkerGraph. The
   serialized bounding box is deserialized to an instance of the
   domain-specific BoundingBox class, and becomes a property value in the
   server's graph.
   - The server prints out some info and writes the received graph to disk
   as a GraphSON file so  we can see that it is true to the client's original
   graph

Note: I'm stretching the notion of "serialized" values somewhat in that, in
these graphs, a serialized value is a record with two fields (or an object
with two member variables): the encoded value itself (in this case, a JSON
blob), and a type identifier.

Josh



On Wed, Jul 7, 2021 at 6:51 AM Joshua Shinavier <jo...@fortytwo.net> wrote:

> Hi Stephen,
>
> Good questions. Let's elevate this discussion (about the specifics of
> graphs and traversal results over Thrift) to the dev list. See inline.
>
>
> On Wed, Jul 7, 2021 at 5:08 AM Stephen Mallette <sp...@gmail.com>
> wrote:
>
>> So, what happens if a returned Vertex contained a ByteBuffer or
>> InetAddress as a property value? I assume the thrift definition has to be
>> adjusted to include those types if you expect them in the results?
>>
>
>
> What you see in the diff, currently, captures the types specifically
> mentioned in Graph.Features (see graph_features.yaml). In order to support
> other types natively, we should update Graph.Features in parallel. Byte
> arrays can be captured using Thrift's binary type. Domain-specific types
> like InetAddress probably should not be built in, just as specific element
> labels and property keys are not built in at this level. However, that is
> not the only possible answer. Certain very common types like IP addresses,
> dates and intervals, units of measurement, etc. *could* be built into the
> type system, but IMO probably shouldn't. Instead, we should give users a
> way of encoding and decoding domain-specific objects using a handful of
> atomic types. InetAddress in this case is encoded either as a string or a
> struct.
>
>
>
>> How would provider specific types (like a Point or special instances of P
>> in JanusGraph) fit into something like this - how would providers (or
>> users) extend on our thrift definitions?
>>
>
> Point is definitely a domain-specific type which you would not see at this
> level of schema. Maybe I can illustrate encoding and decoding
> domain-specific types in the branch; using the current simple type system,
> you could turn the Point into a map with three keys, like "latitude",
> "longitude" and "type". When receiving a map with "type" equal to "Point",
> you turn it back into a native Point object. We could also use a strategy
> similar to Protobuf's Any type, where we send a struct with two fields over
> the wire: one field provides the data of the Point, and the other field
> provides a URL which specifies the type, i.e. how the object should be
> decoded. It is probably worthwhile to add a "record" type variant to
> Graph.Features in any case.
>
>
>
> I think that the idea of having a more strict definition on the types
>> Gremlin supports is starting to materialize given the constraints on
>> serializable types of GraphSON and then further restricted in GraphBinary.
>> We actually have a list of types that haven't changed much in years at this
>> point:
>>
>> https://tinkerpop.apache.org/docs/3.5.0/dev/io/
>>
>
>
> We might want to go through this list with a fine-toothed comb (i.e. we
> probably don't want both a Date atomic type and a Timestamp type unless
> they have different precision/granularity, in which case I would make that
> explicit in the name of the type, e.g. UnixTimeSeconds vs. UnixTimeMillis).
>
>
> I think we could actually even limit them further and then the dream would
>> be to prevent them from being so JVM specific.
>>
>
>
> Yes, I would argue for limiting them to very domain-independent atomic
> types, probably excluding the timestamp type(s) as well as UUID and Class.
> However, as I say it's possible to include a few specialized types if the
> user demand is really high. It's just more stuff which needs to be
> implemented in each Gremlin language variant.
>
>
>
>> It would be nice to elevate the discussion of supported types out of
>> serialization and into the Gremlin language layer itself, which would then
>> in turn drive serialization discussions.
>>
>
>
> That's where I see this going. The specification of Gremlin traversal
> structure in YAML (already illustrated in the branch) translates neatly
> into traversals over the wire using Thrift. To that and the basic graph
> structure specification, we need a specification for other kinds of objects
> which appear in traversal results, such as paths.
>
>
> Josh
>
>
> [original message clipped]
>

Re: [tinkerpop] 03/04: Add a runnable example of a Thrift client sending graphs to a server over TChannel

Posted by Joshua Shinavier <jo...@fortytwo.net>.
Hi Stephen,

Good questions. Let's elevate this discussion (about the specifics of
graphs and traversal results over Thrift) to the dev list. See inline.


On Wed, Jul 7, 2021 at 5:08 AM Stephen Mallette <sp...@gmail.com>
wrote:

> So, what happens if a returned Vertex contained a ByteBuffer or
> InetAddress as a property value? I assume the thrift definition has to be
> adjusted to include those types if you expect them in the results?
>


What you see in the diff, currently, captures the types specifically
mentioned in Graph.Features (see graph_features.yaml). In order to support
other types natively, we should update Graph.Features in parallel. Byte
arrays can be captured using Thrift's binary type. Domain-specific types
like InetAddress probably should not be built in, just as specific element
labels and property keys are not built in at this level. However, that is
not the only possible answer. Certain very common types like IP addresses,
dates and intervals, units of measurement, etc. *could* be built into the
type system, but IMO probably shouldn't. Instead, we should give users a
way of encoding and decoding domain-specific objects using a handful of
atomic types. InetAddress in this case is encoded either as a string or a
struct.



> How would provider specific types (like a Point or special instances of P
> in JanusGraph) fit into something like this - how would providers (or
> users) extend on our thrift definitions?
>

Point is definitely a domain-specific type which you would not see at this
level of schema. Maybe I can illustrate encoding and decoding
domain-specific types in the branch; using the current simple type system,
you could turn the Point into a map with three keys, like "latitude",
"longitude" and "type". When receiving a map with "type" equal to "Point",
you turn it back into a native Point object. We could also use a strategy
similar to Protobuf's Any type, where we send a struct with two fields over
the wire: one field provides the data of the Point, and the other field
provides a URL which specifies the type, i.e. how the object should be
decoded. It is probably worthwhile to add a "record" type variant to
Graph.Features in any case.



I think that the idea of having a more strict definition on the types
> Gremlin supports is starting to materialize given the constraints on
> serializable types of GraphSON and then further restricted in GraphBinary.
> We actually have a list of types that haven't changed much in years at this
> point:
>
> https://tinkerpop.apache.org/docs/3.5.0/dev/io/
>


We might want to go through this list with a fine-toothed comb (i.e. we
probably don't want both a Date atomic type and a Timestamp type unless
they have different precision/granularity, in which case I would make that
explicit in the name of the type, e.g. UnixTimeSeconds vs. UnixTimeMillis).


I think we could actually even limit them further and then the dream would
> be to prevent them from being so JVM specific.
>


Yes, I would argue for limiting them to very domain-independent atomic
types, probably excluding the timestamp type(s) as well as UUID and Class.
However, as I say it's possible to include a few specialized types if the
user demand is really high. It's just more stuff which needs to be
implemented in each Gremlin language variant.



> It would be nice to elevate the discussion of supported types out of
> serialization and into the Gremlin language layer itself, which would then
> in turn drive serialization discussions.
>


That's where I see this going. The specification of Gremlin traversal
structure in YAML (already illustrated in the branch) translates neatly
into traversals over the wire using Thrift. To that and the basic graph
structure specification, we need a specification for other kinds of objects
which appear in traversal results, such as paths.


Josh


[original message clipped]