You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/02/12 14:01:35 UTC

[09/77] [partial] incubator-tinkerpop git commit: moved com/tinkerpop directories to org/apache/tinkerpop

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
new file mode 100644
index 0000000..53b12fd
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
@@ -0,0 +1,347 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.graphson;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.tinkerpop.gremlin.process.T;
+import com.tinkerpop.gremlin.structure.Direction;
+import com.tinkerpop.gremlin.structure.Edge;
+import com.tinkerpop.gremlin.structure.Graph;
+import com.tinkerpop.gremlin.structure.Vertex;
+import com.tinkerpop.gremlin.structure.io.GraphReader;
+import com.tinkerpop.gremlin.structure.util.batch.BatchGraph;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A @{link GraphReader} that constructs a graph from a JSON-based representation of a graph and its elements given
+ * the "legacy" Blueprints 2.x version of GraphSON.  This implementation is specifically for aiding in migration
+ * of graphs from TinkerPop 2.x to TinkerPop 3.x. This reader only reads GraphSON from TinkerPop 2.x that was
+ * generated in {@code GraphSONMode.EXTENDED}.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class LegacyGraphSONReader implements GraphReader {
+    private final ObjectMapper mapper;
+    private final long batchSize;
+
+    public LegacyGraphSONReader(final ObjectMapper mapper, final long batchSize) {
+        this.mapper = mapper;
+        this.batchSize = batchSize;
+    }
+
+    @Override
+    public void readGraph(final InputStream inputStream, final Graph graphToWriteTo) throws IOException {
+        final BatchGraph graph;
+        try {
+            // will throw an exception if not constructed properly
+            graph = BatchGraph.build(graphToWriteTo)
+                    .bufferSize(batchSize).create();
+        } catch (Exception ex) {
+            throw new IOException("Could not instantiate BatchGraph wrapper", ex);
+        }
+
+        final JsonFactory factory = mapper.getFactory();
+        final GraphSONUtility graphson = new GraphSONUtility(graph);
+
+        try (JsonParser parser = factory.createParser(inputStream)) {
+            if (parser.nextToken() != JsonToken.START_OBJECT)
+                throw new IOException("Expected data to start with an Object");
+
+            while (parser.nextToken() != JsonToken.END_OBJECT) {
+                final String fieldName = parser.getCurrentName() == null ? "" : parser.getCurrentName();
+                switch (fieldName) {
+                    case GraphSONTokens.MODE:
+                        parser.nextToken();
+                        final String mode = parser.getText();
+                        if (!mode.equals("EXTENDED"))
+                            throw new IllegalStateException("The legacy GraphSON must be generated with GraphSONMode.EXTENDED");
+                        break;
+                    case GraphSONTokens.VERTICES:
+                        parser.nextToken();
+                        while (parser.nextToken() != JsonToken.END_ARRAY) {
+                            final JsonNode node = parser.readValueAsTree();
+                            graphson.vertexFromJson(node);
+                        }
+                        break;
+                    case GraphSONTokens.EDGES:
+                        parser.nextToken();
+                        while (parser.nextToken() != JsonToken.END_ARRAY) {
+                            final JsonNode node = parser.readValueAsTree();
+                            final Vertex inV = graph.iterators().vertexIterator(GraphSONUtility.getTypedValueFromJsonNode(node.get(GraphSONTokens._IN_V))).next();
+                            final Vertex outV = graph.iterators().vertexIterator(GraphSONUtility.getTypedValueFromJsonNode(node.get(GraphSONTokens._OUT_V))).next();
+                            GraphSONUtility.edgeFromJson(node, outV, inV);
+                        }
+                        break;
+                    default:
+                        throw new IllegalStateException(String.format("Unexpected token in GraphSON - %s", fieldName));
+                }
+            }
+
+            graph.tx().commit();
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+
+    }
+
+    @Override
+    public Iterator<Vertex> readVertices(final InputStream inputStream, final Direction direction,
+                                         final Function<DetachedVertex, Vertex> vertexMaker,
+                                         final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        throw new UnsupportedOperationException("This reader only reads an entire Graph");
+    }
+
+    @Override
+    public Edge readEdge(final InputStream inputStream, final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        throw new UnsupportedOperationException("This reader only reads an entire Graph");
+    }
+
+    @Override
+    public Vertex readVertex(final InputStream inputStream, final Function<DetachedVertex, Vertex> vertexMaker) throws IOException {
+        throw new UnsupportedOperationException("This reader only reads an entire Graph");
+    }
+
+    @Override
+    public Vertex readVertex(final InputStream inputStream, final Direction direction, final Function<DetachedVertex, Vertex> vertexMaker, final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        throw new UnsupportedOperationException("This reader only reads an entire Graph");
+    }
+
+    public static Builder build() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private boolean loadCustomModules = false;
+        private List<SimpleModule> customModules = new ArrayList<>();
+        private long batchSize = BatchGraph.DEFAULT_BUFFER_SIZE;
+        private boolean embedTypes = false;
+
+        private Builder() {
+        }
+
+        /**
+         * Supply a mapper module for serialization/deserialization.
+         */
+        public Builder addCustomModule(final SimpleModule custom) {
+            this.customModules.add(custom);
+            return this;
+        }
+
+        /**
+         * Try to load {@code SimpleModule} instances from the current classpath.  These are loaded in addition to
+         * the one supplied to the {@link #addCustomModule(com.fasterxml.jackson.databind.module.SimpleModule)};
+         */
+        public Builder loadCustomModules(final boolean loadCustomModules) {
+            this.loadCustomModules = loadCustomModules;
+            return this;
+        }
+
+        /**
+         * Number of mutations to perform before a commit is executed.
+         */
+        public Builder batchSize(final long batchSize) {
+            this.batchSize = batchSize;
+            return this;
+        }
+
+        public LegacyGraphSONReader create() {
+            final GraphSONMapper.Builder builder = GraphSONMapper.build();
+            customModules.forEach(builder::addCustomModule);
+            final GraphSONMapper mapper = builder.embedTypes(embedTypes)
+                    .loadCustomModules(loadCustomModules).create();
+            return new LegacyGraphSONReader(mapper.createMapper(), batchSize);
+        }
+    }
+
+    public static class GraphSONUtility {
+        private static final String EMPTY_STRING = "";
+        private final Graph g;
+
+        public GraphSONUtility(final Graph g) {
+            this.g = g;
+        }
+
+        public Vertex vertexFromJson(final JsonNode json) throws IOException {
+            final Map<String, Object> props = readProperties(json);
+
+            final Object vertexId = getTypedValueFromJsonNode(json.get(GraphSONTokens._ID));
+            final Vertex v = g.addVertex(T.id, vertexId);
+
+            for (Map.Entry<String, Object> entry : props.entrySet()) {
+                v.property(entry.getKey(), entry.getValue());
+            }
+
+            return v;
+        }
+
+        public static Edge edgeFromJson(final JsonNode json, final Vertex out, final Vertex in) throws IOException {
+            final Map<String, Object> props = GraphSONUtility.readProperties(json);
+
+            final Object edgeId = getTypedValueFromJsonNode(json.get(GraphSONTokens._ID));
+            final JsonNode nodeLabel = json.get(GraphSONTokens._LABEL);
+            final String label = nodeLabel == null ? EMPTY_STRING : nodeLabel.textValue();
+
+            final Edge e = out.addEdge(label, in, T.id, edgeId);
+            for (Map.Entry<String, Object> entry : props.entrySet()) {
+                e.property(entry.getKey(), entry.getValue());
+            }
+
+            return e;
+        }
+
+        static Map<String, Object> readProperties(final JsonNode node) {
+            final Map<String, Object> map = new HashMap<>();
+
+            final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
+            while (iterator.hasNext()) {
+                final Map.Entry<String, JsonNode> entry = iterator.next();
+
+                if (!isReservedKey(entry.getKey())) {
+                    // it generally shouldn't be as such but graphson containing null values can't be shoved into
+                    // element property keys or it will result in error
+                    final Object o = readProperty(entry.getValue());
+                    if (o != null) {
+                        map.put(entry.getKey(), o);
+                    }
+                }
+            }
+
+            return map;
+        }
+
+        private static boolean isReservedKey(final String key) {
+            return key.equals(GraphSONTokens._ID) || key.equals(GraphSONTokens._TYPE) || key.equals(GraphSONTokens._LABEL)
+                    || key.equals(GraphSONTokens._OUT_V) || key.equals(GraphSONTokens._IN_V);
+        }
+
+        private static Object readProperty(final JsonNode node) {
+            final Object propertyValue;
+
+            if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_UNKNOWN)) {
+                propertyValue = null;
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_BOOLEAN)) {
+                propertyValue = node.get(GraphSONTokens.VALUE).booleanValue();
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_FLOAT)) {
+                propertyValue = Float.parseFloat(node.get(GraphSONTokens.VALUE).asText());
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_BYTE)) {
+                propertyValue = Byte.parseByte(node.get(GraphSONTokens.VALUE).asText());
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_SHORT)) {
+                propertyValue = Short.parseShort(node.get(GraphSONTokens.VALUE).asText());
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_DOUBLE)) {
+                propertyValue = node.get(GraphSONTokens.VALUE).doubleValue();
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_INTEGER)) {
+                propertyValue = node.get(GraphSONTokens.VALUE).intValue();
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_LONG)) {
+                propertyValue = node.get(GraphSONTokens.VALUE).longValue();
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_STRING)) {
+                propertyValue = node.get(GraphSONTokens.VALUE).textValue();
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_LIST)) {
+                propertyValue = readProperties(node.get(GraphSONTokens.VALUE).elements());
+            } else if (node.get(GraphSONTokens.TYPE).textValue().equals(GraphSONTokens.TYPE_MAP)) {
+                propertyValue = readProperties(node.get(GraphSONTokens.VALUE));
+            } else {
+                propertyValue = node.textValue();
+            }
+
+            return propertyValue;
+        }
+
+        private static List readProperties(final Iterator<JsonNode> listOfNodes) {
+            final List<Object> array = new ArrayList<>();
+
+            while (listOfNodes.hasNext()) {
+                array.add(readProperty(listOfNodes.next()));
+            }
+
+            return array;
+        }
+
+        static Object getTypedValueFromJsonNode(final JsonNode node) {
+            Object theValue = null;
+
+            if (node != null && !node.isNull()) {
+                if (node.isBoolean()) {
+                    theValue = node.booleanValue();
+                } else if (node.isDouble()) {
+                    theValue = node.doubleValue();
+                } else if (node.isFloatingPointNumber()) {
+                    theValue = node.floatValue();
+                } else if (node.isInt()) {
+                    theValue = node.intValue();
+                } else if (node.isLong()) {
+                    theValue = node.longValue();
+                } else if (node.isTextual()) {
+                    theValue = node.textValue();
+                } else if (node.isArray()) {
+                    // this is an array so just send it back so that it can be
+                    // reprocessed to its primitive components
+                    theValue = node;
+                } else if (node.isObject()) {
+                    // this is an object so just send it back so that it can be
+                    // reprocessed to its primitive components
+                    theValue = node;
+                } else {
+                    theValue = node.textValue();
+                }
+            }
+
+            return theValue;
+        }
+    }
+
+    public static class GraphSONTokens {
+        public static final String _ID = "_id";
+        public static final String _LABEL = "_label";
+        public static final String _TYPE = "_type";
+        public static final String _OUT_V = "_outV";
+        public static final String _IN_V = "_inV";
+        public static final String VALUE = "value";
+        public static final String TYPE = "type";
+        public static final String TYPE_LIST = "list";
+        public static final String TYPE_STRING = "string";
+        public static final String TYPE_DOUBLE = "double";
+        public static final String TYPE_INTEGER = "integer";
+        public static final String TYPE_FLOAT = "float";
+        public static final String TYPE_MAP = "map";
+        public static final String TYPE_BOOLEAN = "boolean";
+        public static final String TYPE_LONG = "long";
+        public static final String TYPE_SHORT = "short";
+        public static final String TYPE_BYTE = "byte";
+        public static final String TYPE_UNKNOWN = "unknown";
+
+        public static final String VERTICES = "vertices";
+        public static final String EDGES = "edges";
+        public static final String MODE = "mode";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EdgeTerminator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EdgeTerminator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EdgeTerminator.java
new file mode 100644
index 0000000..d409d16
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EdgeTerminator.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+/**
+ * Represents the end of an edge list in a serialization stream.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class EdgeTerminator {
+    public static final EdgeTerminator INSTANCE = new EdgeTerminator();
+    private final boolean terminal;
+
+    private EdgeTerminator() {
+        this.terminal = true;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final EdgeTerminator that = (EdgeTerminator) o;
+
+        return terminal == that.terminal;
+    }
+
+    @Override
+    public int hashCode() {
+        return (terminal ? 1 : 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EntrySerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EntrySerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EntrySerializer.java
new file mode 100644
index 0000000..a089af9
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/EntrySerializer.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
+import java.util.AbstractMap;
+import java.util.Map;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class EntrySerializer extends Serializer<Map.Entry> {
+    @Override
+    public void write(final Kryo kryo, final Output output, final Map.Entry entry) {
+        kryo.writeClassAndObject(output, entry.getKey());
+        kryo.writeClassAndObject(output, entry.getValue());
+    }
+
+    @Override
+    public Map.Entry read(final Kryo kryo, final Input input, final Class<Map.Entry> entryClass) {
+        return new AbstractMap.SimpleEntry(kryo.readClassAndObject(input), kryo.readClassAndObject(input));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GraphSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GraphSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GraphSerializer.java
new file mode 100644
index 0000000..eb964b6
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GraphSerializer.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import com.tinkerpop.gremlin.process.Path;
+import com.tinkerpop.gremlin.process.Traverser;
+import com.tinkerpop.gremlin.structure.Edge;
+import com.tinkerpop.gremlin.structure.Property;
+import com.tinkerpop.gremlin.structure.Vertex;
+import com.tinkerpop.gremlin.structure.VertexProperty;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedPath;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+
+/**
+ * Class used to serialize graph-based objects such as vertices, edges, properties, and paths.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+class GraphSerializer {
+    /**
+     * Serializes any {@link Edge} implementation encountered to a {@link DetachedEdge}.
+     *
+     * @author Stephen Mallette (http://stephen.genoprime.com)
+     */
+    static class EdgeSerializer extends Serializer<Edge> {
+        @Override
+        public void write(final Kryo kryo, final Output output, final Edge edge) {
+            kryo.writeClassAndObject(output, DetachedFactory.detach(edge, true));
+        }
+
+        @Override
+        public Edge read(final Kryo kryo, final Input input, final Class<Edge> edgeClass) {
+            final Object o = kryo.readClassAndObject(input);
+            return (Edge) o;
+        }
+    }
+
+    /**
+     * Serializes any {@link Vertex} implementation encountered to an {@link DetachedVertex}.
+     *
+     * @author Stephen Mallette (http://stephen.genoprime.com)
+     */
+    static class VertexSerializer extends Serializer<Vertex> {
+        public VertexSerializer() {
+        }
+
+        @Override
+        public void write(final Kryo kryo, final Output output, final Vertex vertex) {
+            kryo.writeClassAndObject(output, DetachedFactory.detach(vertex, true));
+        }
+
+        @Override
+        public Vertex read(final Kryo kryo, final Input input, final Class<Vertex> vertexClass) {
+            return (Vertex) kryo.readClassAndObject(input);
+        }
+    }
+
+    /**
+     * Serializes any {@link Property} implementation encountered to an {@link DetachedProperty}.
+     *
+     * @author Stephen Mallette (http://stephen.genoprime.com)
+     */
+    static class PropertySerializer extends Serializer<Property> {
+        public PropertySerializer() {
+        }
+
+        @Override
+        public void write(final Kryo kryo, final Output output, final Property property) {
+            kryo.writeClassAndObject(output, DetachedFactory.detach(property));
+        }
+
+        @Override
+        public Property read(final Kryo kryo, final Input input, final Class<Property> propertyClass) {
+            return (Property) kryo.readClassAndObject(input);
+        }
+    }
+
+    /**
+     * Serializes any {@link VertexProperty} implementation encountered to an {@link DetachedVertexProperty}.
+     *
+     * @author Stephen Mallette (http://stephen.genoprime.com)
+     */
+    static class VertexPropertySerializer extends Serializer<VertexProperty> {
+        public VertexPropertySerializer() {
+        }
+
+        @Override
+        public void write(final Kryo kryo, final Output output, final VertexProperty vertexProperty) {
+            kryo.writeClassAndObject(output, DetachedFactory.detach(vertexProperty, true));
+        }
+
+        @Override
+        public VertexProperty read(final Kryo kryo, final Input input, final Class<VertexProperty> vertexPropertyClass) {
+            return (VertexProperty) kryo.readClassAndObject(input);
+        }
+    }
+
+    /**
+     * Serializes any {@link Path} implementation encountered to an {@link DetachedPath}.
+     *
+     * @author Marko A. Rodriguez (http://markorodriguez.com)
+     */
+    static class PathSerializer extends Serializer<Path> {
+        public PathSerializer() {
+        }
+
+        @Override
+        public void write(final Kryo kryo, final Output output, final Path path) {
+            kryo.writeClassAndObject(output, DetachedFactory.detach(path, false));
+        }
+
+        @Override
+        public Path read(final Kryo kryo, final Input input, final Class<Path> pathClass) {
+            return (Path) kryo.readClassAndObject(input);
+        }
+
+    }
+
+    /**
+     * Serializes any {@link Traverser} implementation encountered via pre-processing with {@link Traverser.Admin#detach()}.
+     *
+     * @author Marko A. Rodriguez (http://markorodriguez.com)
+     */
+    /*static class TraverserSerializer extends Serializer<Traverser.Admin> {
+        public TraverserSerializer() {
+        }
+
+        @Override
+        public void write(final Kryo kryo, final Output output, final Traverser.Admin traverser) {
+            kryo.writeClassAndObject(output, traverser.asAdmin().detach());
+        }
+
+        @Override
+        public Traverser.Admin read(final Kryo kryo, final Input input, final Class<Traverser.Admin> traverser) {
+            return (Traverser.Admin) kryo.readClassAndObject(input);
+        }
+
+    }*/
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GremlinClassResolver.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GremlinClassResolver.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GremlinClassResolver.java
new file mode 100644
index 0000000..f9d04de
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/GremlinClassResolver.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.ClassResolver;
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.KryoException;
+import com.esotericsoftware.kryo.Registration;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import com.esotericsoftware.kryo.util.IdentityObjectIntMap;
+import com.esotericsoftware.kryo.util.IntMap;
+import com.esotericsoftware.kryo.util.ObjectMap;
+import com.tinkerpop.gremlin.process.Path;
+import com.tinkerpop.gremlin.structure.Edge;
+import com.tinkerpop.gremlin.structure.Property;
+import com.tinkerpop.gremlin.structure.Vertex;
+import com.tinkerpop.gremlin.structure.VertexProperty;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedPath;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+
+import static com.esotericsoftware.kryo.util.Util.getWrapperClass;
+
+/**
+ * This mapper implementation of the {@code ClassResolver} helps ensure that all Vertex and Edge concrete classes
+ * get properly serialized and deserialized by stripping them of their concrete class name so that they are treated
+ * generically.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class GremlinClassResolver implements ClassResolver {
+    static public final byte NAME = -1;
+
+    protected Kryo kryo;
+
+    protected final IntMap<Registration> idToRegistration = new IntMap<>();
+    protected final ObjectMap<Class, Registration> classToRegistration = new ObjectMap<>();
+
+    protected IdentityObjectIntMap<Class> classToNameId;
+    protected IntMap<Class> nameIdToClass;
+    protected ObjectMap<String, Class> nameToClass;
+    protected int nextNameId;
+
+    private int memoizedClassId = -1;
+    private Registration memoizedClassIdValue;
+    private Class memoizedClass;
+    private Registration memoizedClassValue;
+
+    @Override
+    public void setKryo(Kryo kryo) {
+        this.kryo = kryo;
+    }
+
+    @Override
+    public Registration register(final Registration registration) {
+        if (null == registration) throw new IllegalArgumentException("Registration cannot be null.");
+        if (registration.getId() != NAME) idToRegistration.put(registration.getId(), registration);
+
+        classToRegistration.put(registration.getType(), registration);
+        if (registration.getType().isPrimitive())
+            classToRegistration.put(getWrapperClass(registration.getType()), registration);
+        return registration;
+    }
+
+    @Override
+    public Registration registerImplicit(final Class type) {
+        return register(new Registration(type, kryo.getDefaultSerializer(type), NAME));
+    }
+
+    @Override
+    public Registration getRegistration(final Class clazz) {
+        // force all instances of Vertex, Edge, VertexProperty, etc. to their respective interface
+        final Class type;
+        if (!DetachedVertex.class.isAssignableFrom(clazz) && Vertex.class.isAssignableFrom(clazz))
+            type = Vertex.class;
+        else if (!DetachedEdge.class.isAssignableFrom(clazz) && Edge.class.isAssignableFrom(clazz))
+            type = Edge.class;
+        else if (!DetachedVertexProperty.class.isAssignableFrom(clazz) && VertexProperty.class.isAssignableFrom(clazz))
+            type = VertexProperty.class;
+        else if (!DetachedProperty.class.isAssignableFrom(clazz) && !DetachedVertexProperty.class.isAssignableFrom(clazz) && Property.class.isAssignableFrom(clazz))
+            type = Property.class;
+        else if (!DetachedPath.class.isAssignableFrom(clazz) && Path.class.isAssignableFrom(clazz))
+            type = Path.class;
+        else
+            type = clazz;
+
+        if (type == memoizedClass) return memoizedClassValue;
+        final Registration registration = classToRegistration.get(type);
+        if (registration != null) {
+            memoizedClass = type;
+            memoizedClassValue = registration;
+        }
+
+        return registration;
+    }
+
+    @Override
+    public Registration getRegistration(final int classID) {
+        return idToRegistration.get(classID);
+    }
+
+    @Override
+    public Registration writeClass(final Output output, final Class type) {
+        if (null == type) {
+            output.writeVarInt(Kryo.NULL, true);
+            return null;
+        }
+
+        final Registration registration = kryo.getRegistration(type);
+        if (registration.getId() == NAME)
+            writeName(output, type);
+        else
+            output.writeVarInt(registration.getId() + 2, true);
+
+        return registration;
+    }
+
+    protected void writeName(final Output output, final Class type) {
+        output.writeVarInt(NAME + 2, true);
+        if (classToNameId != null) {
+            final int nameId = classToNameId.get(type, -1);
+            if (nameId != -1) {
+                output.writeVarInt(nameId, true);
+                return;
+            }
+        }
+        // Only write the class name the first time encountered in object graph.
+        final int nameId = nextNameId++;
+        if (classToNameId == null) classToNameId = new IdentityObjectIntMap<>();
+        classToNameId.put(type, nameId);
+        output.writeVarInt(nameId, true);
+        output.writeString(type.getName());
+    }
+
+    @Override
+    public Registration readClass(final Input input) {
+        final int classID = input.readVarInt(true);
+        switch (classID) {
+            case Kryo.NULL:
+                return null;
+            case NAME + 2: // Offset for NAME and NULL.
+                return readName(input);
+        }
+
+        if (classID == memoizedClassId) return memoizedClassIdValue;
+        final Registration registration = idToRegistration.get(classID - 2);
+        if (registration == null) throw new KryoException("Encountered unregistered class ID: " + (classID - 2));
+        memoizedClassId = classID;
+        memoizedClassIdValue = registration;
+        return registration;
+    }
+
+    protected Registration readName(final Input input) {
+        final int nameId = input.readVarInt(true);
+        if (nameIdToClass == null) nameIdToClass = new IntMap<>();
+        Class type = nameIdToClass.get(nameId);
+        if (type == null) {
+            // Only read the class name the first time encountered in object graph.
+            final String className = input.readString();
+            type = getTypeByName(className);
+            if (type == null) {
+                try {
+                    type = Class.forName(className, false, kryo.getClassLoader());
+                } catch (ClassNotFoundException ex) {
+                    throw new KryoException("Unable to find class: " + className, ex);
+                }
+                if (nameToClass == null) nameToClass = new ObjectMap<>();
+                nameToClass.put(className, type);
+            }
+            nameIdToClass.put(nameId, type);
+        }
+        return kryo.getRegistration(type);
+    }
+
+    protected Class<?> getTypeByName(final String className) {
+        return nameToClass != null ? nameToClass.get(className) : null;
+    }
+
+    @Override
+    public void reset() {
+        if (!kryo.isRegistrationRequired()) {
+            if (classToNameId != null) classToNameId.clear();
+            if (nameIdToClass != null) nameIdToClass.clear();
+            nextNameId = 0;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoMapper.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoMapper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoMapper.java
new file mode 100644
index 0000000..bb31f0f
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoMapper.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.KryoSerializable;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import com.esotericsoftware.kryo.util.DefaultStreamFactory;
+import com.esotericsoftware.kryo.util.MapReferenceResolver;
+import com.tinkerpop.gremlin.process.Path;
+import com.tinkerpop.gremlin.process.T;
+import com.tinkerpop.gremlin.process.computer.MapReduce;
+import com.tinkerpop.gremlin.process.computer.util.MapMemory;
+import com.tinkerpop.gremlin.process.graph.util.Tree;
+import com.tinkerpop.gremlin.process.traverser.B_O_PA_S_SE_SL_Traverser;
+import com.tinkerpop.gremlin.process.traverser.B_O_P_PA_S_SE_SL_Traverser;
+import com.tinkerpop.gremlin.process.traverser.B_O_Traverser;
+import com.tinkerpop.gremlin.process.traverser.O_Traverser;
+import com.tinkerpop.gremlin.process.util.BulkSet;
+import com.tinkerpop.gremlin.process.util.metric.MutableMetrics;
+import com.tinkerpop.gremlin.process.util.metric.StandardTraversalMetrics;
+import com.tinkerpop.gremlin.process.util.TraverserSet;
+import com.tinkerpop.gremlin.structure.Contains;
+import com.tinkerpop.gremlin.structure.Direction;
+import com.tinkerpop.gremlin.structure.Edge;
+import com.tinkerpop.gremlin.structure.Property;
+import com.tinkerpop.gremlin.structure.Vertex;
+import com.tinkerpop.gremlin.structure.VertexProperty;
+import com.tinkerpop.gremlin.structure.io.Mapper;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedPath;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.javatuples.Triplet;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * A {@link Mapper} implementation for Kryo.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class KryoMapper implements Mapper<Kryo> {
+    static final byte[] GIO = "gio".getBytes();
+    private final List<Triplet<Class, Function<Kryo, Serializer>, Integer>> serializationList;
+    private final HeaderWriter headerWriter;
+    private final HeaderReader headerReader;
+    private final byte[] versionedHeader;
+
+    public static final byte DEFAULT_EXTENDED_VERSION = Byte.MIN_VALUE;
+
+    private KryoMapper(final List<Triplet<Class, Function<Kryo, Serializer>, Integer>> serializationList,
+                       final HeaderWriter headerWriter,
+                       final HeaderReader headerReader) {
+        this.serializationList = serializationList;
+        this.headerWriter = headerWriter;
+        this.headerReader = headerReader;
+
+        final Output out = new Output(32);
+        try {
+            this.headerWriter.write(createMapper(), out);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+        this.versionedHeader = out.toBytes();
+    }
+
+    @Override
+    public Kryo createMapper() {
+        final Kryo kryo = new Kryo(new GremlinClassResolver(), new MapReferenceResolver(), new DefaultStreamFactory());
+        kryo.addDefaultSerializer(Map.Entry.class, new EntrySerializer());
+        kryo.setRegistrationRequired(true);
+        serializationList.forEach(p -> {
+            final Function<Kryo, Serializer> serializer = p.getValue1();
+            if (null == serializer)
+                kryo.register(p.getValue0(), kryo.getDefaultSerializer(p.getValue0()), p.getValue2());
+            else
+                kryo.register(p.getValue0(), serializer.apply(kryo), p.getValue2());
+        });
+        return kryo;
+    }
+
+    public HeaderWriter getHeaderWriter() {
+        return headerWriter;
+    }
+
+    public HeaderReader getHeaderReader() {
+        return headerReader;
+    }
+
+    /**
+     * Gets the header for a Gremlin Kryo file, which is based on the version of Gremlin Kryo that is constructed
+     * via the builder classes.
+     */
+    public byte[] getVersionedHeader() {
+        return versionedHeader;
+    }
+
+    @FunctionalInterface
+    public interface HeaderReader {
+        public void read(final Kryo kryo, final Input input) throws IOException;
+    }
+
+    @FunctionalInterface
+    public interface HeaderWriter {
+        public void write(final Kryo kryo, final Output output) throws IOException;
+    }
+
+    /**
+     * Use a specific version of Gremlin Kryo.
+     */
+    public static Builder build(final Version version) {
+        return version.getBuilder();
+    }
+
+    /**
+     * Use the most current version of Gremlin Kryo.
+     */
+    public static Builder build() {
+        return Version.V_1_0_0.getBuilder();
+    }
+
+    public static interface Builder {
+        /**
+         * Add mapper classes to serializes with kryo using standard serialization.
+         */
+        public Builder addCustom(final Class... custom);
+
+        /**
+         * Add mapper class to serializes with mapper serialization.
+         */
+        public Builder addCustom(final Class clazz, final Serializer serializer);
+
+        /**
+         * Add mapper class to serializes with mapper serialization as returned from a {@link Function}.
+         */
+        public Builder addCustom(final Class clazz, final Function<Kryo, Serializer> serializer);
+
+        /**
+         * If using mapper classes it might be useful to tag the version stamped to the serialization with a mapper
+         * value, such that Kryo serialization at 1.0.0 would have a fourth byte for an extended version.  The user
+         * supplied fourth byte can then be used to ensure the right deserializer is used to read the data. If this
+         * value is not supplied then it is written as {@link Byte#MIN_VALUE}. The value supplied here should be greater
+         * than or equal to zero.
+         */
+        public Builder extendedVersion(final byte extendedVersion);
+
+        /**
+         * By default the {@link #extendedVersion(byte)} is checked against what is read from an input source and if
+         * those values are equal the version being read is considered "compliant".  To alter this behavior, supply a
+         * mapper compliance {@link Predicate} to evaluate the value read from the input source (i.e. first argument)
+         * and the value marked in the {@code GremlinKryo} instance {i.e. second argument}.  Supplying this function is
+         * useful when versions require backward compatibility or other more complex checks.  This function is only used
+         * if the {@link #extendedVersion(byte)} is set to something other than its default.
+         */
+        public Builder compliant(final BiPredicate<Byte, Byte> compliant);
+
+        public KryoMapper create();
+    }
+
+    public enum Version {
+        V_1_0_0(BuilderV1d0.class);
+
+        private final Class<? extends Builder> builder;
+
+        private Version(final Class<? extends Builder> builder) {
+            this.builder = builder;
+        }
+
+        Builder getBuilder() {
+            try {
+                return builder.newInstance();
+            } catch (Exception x) {
+                throw new RuntimeException("GremlinKryo Builder implementation cannot be instantiated", x);
+            }
+        }
+    }
+
+    public static class BuilderV1d0 implements Builder {
+
+        /**
+         * Map with one entry that is used so that it is possible to get the class of LinkedHashMap.Entry.
+         */
+        private static final LinkedHashMap m = new LinkedHashMap() {{
+            put("junk", "dummy");
+        }};
+
+        private static final Class LINKED_HASH_MAP_ENTRY_CLASS = m.entrySet().iterator().next().getClass();
+
+        /**
+         * Note that the following are pre-registered boolean, Boolean, byte, Byte, char, Character, double, Double,
+         * int, Integer, float, Float, long, Long, short, Short, String, void.
+         */
+        private final List<Triplet<Class, Function<Kryo, Serializer>, Integer>> serializationList = new ArrayList<Triplet<Class, Function<Kryo, Serializer>, Integer>>() {{
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(byte[].class, null, 25));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(char[].class, null, 26));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(short[].class, null, 27));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(int[].class, null, 28));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(long[].class, null, 29));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(float[].class, null, 30));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(double[].class, null, 31));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(String[].class, null, 32));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Object[].class, null, 33));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(ArrayList.class, null, 10));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(BigInteger.class, null, 34));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(BigDecimal.class, null, 35));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Calendar.class, null, 39));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Class.class, null, 41));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collection.class, null, 37));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.EMPTY_LIST.getClass(), null, 51));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.EMPTY_MAP.getClass(), null, 52));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.EMPTY_SET.getClass(), null, 53));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.singleton(null).getClass(), null, 54));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.singletonList(null).getClass(), null, 24));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Collections.singletonMap(null, null).getClass(), null, 23));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Contains.class, null, 49));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Currency.class, null, 40));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Date.class, null, 38));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Direction.class, null, 12));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(DetachedEdge.class, null, 21));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(DetachedVertexProperty.class, null, 20));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(DetachedProperty.class, null, 18));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(DetachedVertex.class, null, 19));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(DetachedPath.class, null, 60));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(EdgeTerminator.class, null, 14));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(EnumSet.class, null, 46));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(HashMap.class, null, 11));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(HashMap.Entry.class, null, 16));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(KryoSerializable.class, null, 36));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(LinkedHashMap.class, null, 47));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(LinkedHashSet.class, null, 71));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(LINKED_HASH_MAP_ENTRY_CLASS, null, 15));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Locale.class, null, 22));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(StringBuffer.class, null, 43));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(StringBuilder.class, null, 44));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(T.class, null, 48));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(TimeZone.class, null, 42));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(TreeMap.class, null, 45));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(TreeSet.class, null, 50));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(UUID.class, kryo -> new UUIDSerializer(), 17));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(URI.class, kryo -> new URISerializer(), 72));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(VertexTerminator.class, null, 13));
+
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Edge.class, kryo -> new GraphSerializer.EdgeSerializer(), 65));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Vertex.class, kryo -> new GraphSerializer.VertexSerializer(), 66));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Property.class, kryo -> new GraphSerializer.PropertySerializer(), 67));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(VertexProperty.class, kryo -> new GraphSerializer.VertexPropertySerializer(), 68));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Path.class, kryo -> new GraphSerializer.PathSerializer(), 59));
+            // HACK!
+            //add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Traverser.Admin.class, kryo -> new GraphSerializer.TraverserSerializer(), 55));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(B_O_Traverser.class, null, 75));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(O_Traverser.class, null, 76));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(B_O_P_PA_S_SE_SL_Traverser.class, null, 77));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(B_O_PA_S_SE_SL_Traverser.class, null, 78));   // ***LAST ID***
+
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(TraverserSet.class, null, 58));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(Tree.class, null, 61));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(HashSet.class, null, 62));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(BulkSet.class, null, 64));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(MutableMetrics.class, null, 69));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(StandardTraversalMetrics.class, null, 70));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(MapMemory.class, null, 73));
+            add(Triplet.<Class, Function<Kryo, Serializer>, Integer>with(MapReduce.NullObject.class, null, 74));
+        }};
+
+        private static final byte major = 1;
+        private static final byte minor = 0;
+        private static final byte patchLevel = 0;
+
+        private byte extendedVersion = DEFAULT_EXTENDED_VERSION;
+        private BiPredicate<Byte, Byte> compliant = (readExt, serExt) -> readExt.equals(serExt);
+
+        /**
+         * Starts numbering classes for Kryo serialization at 65536 to leave room for future usage by TinkerPop.
+         */
+        private final AtomicInteger currentSerializationId = new AtomicInteger(65536);
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Builder addCustom(final Class... custom) {
+            if (custom != null && custom.length > 0)
+                serializationList.addAll(Arrays.asList(custom).stream()
+                        .map(c -> Triplet.<Class, Function<Kryo, Serializer>, Integer>with(c, null, currentSerializationId.getAndIncrement()))
+                        .collect(Collectors.<Triplet<Class, Function<Kryo, Serializer>, Integer>>toList()));
+            return this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Builder addCustom(final Class clazz, final Serializer serializer) {
+            serializationList.add(Triplet.with(clazz, kryo -> serializer, currentSerializationId.getAndIncrement()));
+            return this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Builder addCustom(final Class clazz, final Function<Kryo, Serializer> serializer) {
+            serializationList.add(Triplet.with(clazz, serializer, currentSerializationId.getAndIncrement()));
+            return this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Builder extendedVersion(final byte extendedVersion) {
+            if (extendedVersion > DEFAULT_EXTENDED_VERSION && extendedVersion < 0)
+                throw new IllegalArgumentException("The extendedVersion must be greater than zero");
+
+            this.extendedVersion = extendedVersion;
+            return this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Builder compliant(final BiPredicate<Byte, Byte> compliant) {
+            if (null == compliant)
+                throw new IllegalArgumentException("compliant");
+
+            this.compliant = compliant;
+            return this;
+        }
+
+        @Override
+        public KryoMapper create() {
+            return new KryoMapper(serializationList, this::writeHeader, this::readHeader);
+        }
+
+        private void writeHeader(final Kryo kryo, final Output output) throws IOException {
+            // 32 byte header total
+            output.writeBytes(GIO);
+
+            // some space for later
+            output.writeBytes(new byte[25]);
+
+            // version x.y.z
+            output.writeByte(major);
+            output.writeByte(minor);
+            output.writeByte(patchLevel);
+            output.writeByte(extendedVersion);
+        }
+
+        private void readHeader(final Kryo kryo, final Input input) throws IOException {
+            if (!Arrays.equals(GIO, input.readBytes(3)))
+                throw new IOException("Invalid format - first three bytes of header do not match expected value");
+
+            // skip the next 25 bytes in v1
+            input.readBytes(25);
+
+            // final three bytes of header are the version which should be 1.0.0
+            final byte[] version = input.readBytes(3);
+            final byte extension = input.readByte();
+
+            // direct match on version for now
+            if (version[0] != major || version[1] != minor || version[2] != patchLevel)
+                throw new IOException(String.format(
+                        "The version [%s.%s.%s] in the stream cannot be understood by this reader",
+                        version[0], version[1], version[2]));
+
+            if (extendedVersion >= 0 && !compliant.test(extension, extendedVersion))
+                throw new IOException(String.format(
+                        "The extension [%s] in the input source is not compliant with this configuration of GremlinKryo - [%s]",
+                        extension, extendedVersion));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoReader.java
new file mode 100644
index 0000000..25df118
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoReader.java
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import com.tinkerpop.gremlin.process.T;
+import com.tinkerpop.gremlin.structure.*;
+import com.tinkerpop.gremlin.structure.io.GraphReader;
+import com.tinkerpop.gremlin.structure.util.batch.BatchGraph;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
+
+/**
+ * The {@link GraphReader} for the Gremlin Structure serialization format based on Kryo.  The format is meant to be
+ * non-lossy in terms of Gremlin Structure to Gremlin Structure migrations (assuming both structure implementations
+ * support the same graph features).
+ * <br/>
+ * This implementation is not thread-safe.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public class KryoReader implements GraphReader {
+    private final Kryo kryo;
+    private final KryoMapper.HeaderReader headerReader;
+
+    private final long batchSize;
+    private final String vertexIdKey;
+    private final String edgeIdKey;
+
+    private final File tempFile;
+
+    final AtomicLong counter = new AtomicLong(0);
+
+    private KryoReader(final File tempFile, final long batchSize,
+                       final String vertexIdKey, final String edgeIdKey,
+                       final KryoMapper kryoMapper) {
+        this.kryo = kryoMapper.createMapper();
+        this.headerReader = kryoMapper.getHeaderReader();
+        this.vertexIdKey = vertexIdKey;
+        this.edgeIdKey = edgeIdKey;
+        this.tempFile = tempFile;
+        this.batchSize = batchSize;
+    }
+
+    @Override
+    public Iterator<Vertex> readVertices(final InputStream inputStream, final Direction direction,
+                                         final Function<DetachedVertex, Vertex> vertexMaker,
+                                         final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        final Input input = new Input(inputStream);
+        return new Iterator<Vertex>() {
+            @Override
+            public boolean hasNext() {
+                return !input.eof();
+            }
+
+            @Override
+            public Vertex next() {
+                try {
+                    final Vertex v = readVertex(direction, vertexMaker, edgeMaker, input);
+
+                    // read the vertex terminator
+                    kryo.readClassAndObject(input);
+
+                    return v;
+                } catch (Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        };
+    }
+
+    @Override
+    public Edge readEdge(final InputStream inputStream, final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        final Input input = new Input(inputStream);
+        this.headerReader.read(kryo, input);
+        final Object o = kryo.readClassAndObject(input);
+        return edgeMaker.apply((DetachedEdge) o);
+    }
+
+    @Override
+    public Vertex readVertex(final InputStream inputStream, final Function<DetachedVertex, Vertex> vertexMaker) throws IOException {
+        return readVertex(inputStream, null, vertexMaker, null);
+    }
+
+    @Override
+    public Vertex readVertex(final InputStream inputStream, final Direction direction, Function<DetachedVertex, Vertex> vertexMaker, final Function<DetachedEdge, Edge> edgeMaker) throws IOException {
+        final Input input = new Input(inputStream);
+        return readVertex(direction, vertexMaker, edgeMaker, input);
+    }
+
+    @Override
+    public void readGraph(final InputStream inputStream, final Graph graphToWriteTo) throws IOException {
+        this.counter.set(0);
+        final Input input = new Input(inputStream);
+        this.headerReader.read(kryo, input);
+
+        final BatchGraph graph;
+        try {
+            // will throw an exception if not constructed properly
+            graph = BatchGraph.build(graphToWriteTo)
+                    .vertexIdKey(vertexIdKey)
+                    .edgeIdKey(edgeIdKey)
+                    .bufferSize(batchSize).create();
+        } catch (Exception ex) {
+            throw new IOException("Could not instantiate BatchGraph wrapper", ex);
+        }
+
+        try (final Output output = new Output(new FileOutputStream(tempFile))) {
+            final boolean supportedMemory = input.readBoolean();
+            if (supportedMemory) {
+                // if the graph that serialized the data supported sideEffects then the sideEffects needs to be read
+                // to advance the reader forward.  if the graph being read into doesn't support the sideEffects
+                // then we just setting the data to sideEffects.
+                final Map<String, Object> memMap = (Map<String, Object>) kryo.readObject(input, HashMap.class);
+                if (graphToWriteTo.features().graph().variables().supportsVariables()) {
+                    final Graph.Variables variables = graphToWriteTo.variables();
+                    memMap.forEach(variables::set);
+                }
+            }
+
+            final boolean hasSomeVertices = input.readBoolean();
+            if (hasSomeVertices) {
+                final List<Object> vertexArgs = new ArrayList<>();
+                while (!input.eof()) {
+                    final DetachedVertex current = (DetachedVertex) kryo.readClassAndObject(input);
+                    appendToArgList(vertexArgs, T.id, current.id());
+                    appendToArgList(vertexArgs, T.label, current.label());
+
+                    final Vertex v = graph.addVertex(vertexArgs.toArray());
+                    vertexArgs.clear();
+                    current.iterators().propertyIterator().forEachRemaining(p -> createVertexProperty(graphToWriteTo, v, p, false));
+
+                    // the gio file should have been written with a direction specified
+                    final boolean hasDirectionSpecified = input.readBoolean();
+                    final Direction directionInStream = kryo.readObject(input, Direction.class);
+                    final Direction directionOfEdgeBatch = kryo.readObject(input, Direction.class);
+
+                    // graph serialization requires that a direction be specified in the stream and that the
+                    // direction of the edges be OUT
+                    if (!hasDirectionSpecified || directionInStream != Direction.OUT || directionOfEdgeBatch != Direction.OUT)
+                        throw new IllegalStateException(String.format("Stream must specify edge direction and that direction must be %s", Direction.OUT));
+
+                    // if there are edges then read them to end and write to temp, otherwise read what should be
+                    // the vertex terminator
+                    if (!input.readBoolean())
+                        kryo.readClassAndObject(input);
+                    else
+                        readToEndOfEdgesAndWriteToTemp(input, output);
+                }
+            }
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+        // done writing to temp
+
+        // start reading in the edges now from the temp file
+        try (final Input edgeInput = new Input(new FileInputStream(tempFile))) {
+            readFromTempEdges(edgeInput, graph);
+            graph.tx().commit();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            throw new IOException(ex);
+        } finally {
+            deleteTempFileSilently();
+        }
+    }
+
+    private static void createVertexProperty(final Graph graphToWriteTo, final Vertex v, final VertexProperty<Object> p, final boolean hidden) {
+        final List<Object> propertyArgs = new ArrayList<>();
+        if (graphToWriteTo.features().vertex().properties().supportsUserSuppliedIds())
+            appendToArgList(propertyArgs, T.id, p.id());
+        p.iterators().propertyIterator().forEachRemaining(it -> appendToArgList(propertyArgs, it.key(), it.value()));
+        v.property(p.key(), p.value(), propertyArgs.toArray());
+    }
+
+    private static void appendToArgList(final List<Object> propertyArgs, final Object key, final Object val) {
+        propertyArgs.add(key);
+        propertyArgs.add(val);
+    }
+
+    private Vertex readVertex(final Direction directionRequested, final Function<DetachedVertex, Vertex> vertexMaker,
+                              final Function<DetachedEdge, Edge> edgeMaker, final Input input) throws IOException {
+        if (null != directionRequested && null == edgeMaker)
+            throw new IllegalArgumentException("If a directionRequested is specified then an edgeAdder function should also be specified");
+
+        this.headerReader.read(kryo, input);
+
+        final DetachedVertex detachedVertex = (DetachedVertex) kryo.readClassAndObject(input);
+        final Vertex v = vertexMaker.apply(detachedVertex);
+
+        final boolean streamContainsEdgesInSomeDirection = input.readBoolean();
+        if (!streamContainsEdgesInSomeDirection && directionRequested != null)
+            throw new IllegalStateException(String.format("The direction %s was requested but no attempt was made to serialize edges into this stream", directionRequested));
+
+        // if there are edges in the stream and the direction is not present then the rest of the stream is
+        // simply ignored
+        if (directionRequested != null) {
+            final Direction directionsInStream = kryo.readObject(input, Direction.class);
+            if (directionsInStream != Direction.BOTH && directionsInStream != directionRequested)
+                throw new IllegalStateException(String.format("Stream contains %s edges, but requesting %s", directionsInStream, directionRequested));
+
+            final Direction firstDirection = kryo.readObject(input, Direction.class);
+            if (firstDirection == Direction.OUT && (directionRequested == Direction.BOTH || directionRequested == Direction.OUT))
+                readEdges(input, edgeMaker);
+            else {
+                // requested direction in, but BOTH must be serialized so skip this.  the illegalstateexception
+                // prior to this IF should  have caught a problem where IN is not supported at all
+                if (firstDirection == Direction.OUT && directionRequested == Direction.IN)
+                    skipEdges(input);
+            }
+
+            if (directionRequested == Direction.BOTH || directionRequested == Direction.IN) {
+                // if the first direction was OUT then it was either read or skipped.  in that case, the marker
+                // of the stream is currently ready to read the IN direction. otherwise it's in the perfect place
+                // to start reading edges
+                if (firstDirection == Direction.OUT)
+                    kryo.readObject(input, Direction.class);
+
+                readEdges(input, edgeMaker);
+            }
+        }
+
+        return v;
+    }
+
+    private void readEdges(final Input input, final Function<DetachedEdge, Edge> edgeMaker) {
+        if (input.readBoolean()) {
+            Object next = kryo.readClassAndObject(input);
+            while (!next.equals(EdgeTerminator.INSTANCE)) {
+                final DetachedEdge detachedEdge = (DetachedEdge) next;
+                edgeMaker.apply(detachedEdge);
+                next = kryo.readClassAndObject(input);
+            }
+        }
+    }
+
+    private void skipEdges(final Input input) {
+        if (input.readBoolean()) {
+            Object next = kryo.readClassAndObject(input);
+            while (!next.equals(EdgeTerminator.INSTANCE)) {
+                // next edge to skip or the terminator
+                next = kryo.readClassAndObject(input);
+            }
+        }
+    }
+
+    /**
+     * Reads through the all the edges for a vertex and writes the edges to a temp file which will be read later.
+     */
+    private void readToEndOfEdgesAndWriteToTemp(final Input input, final Output output) throws IOException {
+        Object next = kryo.readClassAndObject(input);
+        while (!next.equals(EdgeTerminator.INSTANCE)) {
+            kryo.writeClassAndObject(output, next);
+
+            // next edge or terminator
+            next = kryo.readClassAndObject(input);
+        }
+
+        // this should be the vertex terminator
+        kryo.readClassAndObject(input);
+
+        kryo.writeClassAndObject(output, EdgeTerminator.INSTANCE);
+        kryo.writeClassAndObject(output, VertexTerminator.INSTANCE);
+    }
+
+
+    /**
+     * Read the edges from the temp file and load them to the graph.
+     */
+    private void readFromTempEdges(final Input input, final Graph graphToWriteTo) {
+        final List<Object> edgeArgs = new ArrayList<>();
+        while (!input.eof()) {
+            // in this case the outId is the id assigned by the graph
+            Object next = kryo.readClassAndObject(input);
+            while (!next.equals(EdgeTerminator.INSTANCE)) {
+                final DetachedEdge detachedEdge = (DetachedEdge) next;
+                final Vertex vOut = graphToWriteTo.iterators().vertexIterator(detachedEdge.iterators().vertexIterator(Direction.OUT).next().id()).next();
+                final Vertex inV = graphToWriteTo.iterators().vertexIterator(detachedEdge.iterators().vertexIterator(Direction.IN).next().id()).next();
+
+                detachedEdge.iterators().propertyIterator().forEachRemaining(p -> edgeArgs.addAll(Arrays.asList(p.key(), p.value())));
+
+                appendToArgList(edgeArgs, T.id, detachedEdge.id());
+
+                vOut.addEdge(detachedEdge.label(), inV, edgeArgs.toArray());
+
+                edgeArgs.clear();
+                next = kryo.readClassAndObject(input);
+            }
+
+            // vertex terminator
+            kryo.readClassAndObject(input);
+        }
+    }
+
+    @SuppressWarnings("ResultOfMethodCallIgnored")
+    private void deleteTempFileSilently() {
+        try {
+            tempFile.delete();
+        } catch (Exception ignored) {
+        }
+    }
+
+    public static Builder build() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private File tempFile;
+        private long batchSize = BatchGraph.DEFAULT_BUFFER_SIZE;
+        private String vertexIdKey = T.id.getAccessor();
+        private String edgeIdKey = T.id.getAccessor();
+
+        /**
+         * Always use the most recent kryo version by default
+         */
+        private KryoMapper kryoMapper = KryoMapper.build().create();
+
+        private Builder() {
+            this.tempFile = new File(UUID.randomUUID() + ".tmp");
+        }
+
+        /**
+         * Set the size between commits when reading into the {@link Graph} instance.  This value defaults to
+         * {@link BatchGraph#DEFAULT_BUFFER_SIZE}.
+         */
+        public Builder batchSize(final long batchSize) {
+            this.batchSize = batchSize;
+            return this;
+        }
+
+        /**
+         * Supply a mapper {@link KryoMapper} instance to use as the serializer for the {@code KryoWriter}.
+         */
+        public Builder mapper(final KryoMapper kryoMapper) {
+            this.kryoMapper = kryoMapper;
+            return this;
+        }
+
+        /**
+         * The name of the key to supply to
+         * {@link com.tinkerpop.gremlin.structure.util.batch.BatchGraph.Builder#vertexIdKey} when reading data into
+         * the {@link Graph}.
+         */
+        public Builder vertexIdKey(final String vertexIdKey) {
+            this.vertexIdKey = vertexIdKey;
+            return this;
+        }
+
+        /**
+         * The name of the key to supply to
+         * {@link com.tinkerpop.gremlin.structure.util.batch.BatchGraph.Builder#edgeIdKey} when reading data into
+         * the {@link Graph}.
+         */
+        public Builder edgeIdKey(final String edgeIdKey) {
+            this.edgeIdKey = edgeIdKey;
+            return this;
+        }
+
+        /**
+         * The reader requires a working directory to write temp files to.  If this value is not set, it will write
+         * the temp file to the local directory.
+         */
+        public Builder workingDirectory(final String workingDirectory) {
+            final File f = new File(workingDirectory);
+            if (!f.exists() || !f.isDirectory())
+                throw new IllegalArgumentException(String.format("%s is not a directory or does not exist", workingDirectory));
+
+            tempFile = new File(workingDirectory + File.separator + UUID.randomUUID() + ".tmp");
+            return this;
+        }
+
+        public KryoReader create() {
+            return new KryoReader(tempFile, batchSize, this.vertexIdKey, this.edgeIdKey, this.kryoMapper);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoWriter.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoWriter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoWriter.java
new file mode 100644
index 0000000..b1af298
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/KryoWriter.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Output;
+import com.tinkerpop.gremlin.structure.Direction;
+import com.tinkerpop.gremlin.structure.Edge;
+import com.tinkerpop.gremlin.structure.Element;
+import com.tinkerpop.gremlin.structure.Graph;
+import com.tinkerpop.gremlin.structure.Vertex;
+import com.tinkerpop.gremlin.structure.io.GraphWriter;
+import com.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.UUID;
+
+/**
+ * The {@link GraphWriter} for the Gremlin Structure serialization format based on Kryo.  The format is meant to be
+ * non-lossy in terms of Gremlin Structure to Gremlin Structure migrations (assuming both structure implementations
+ * support the same graph features).
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class KryoWriter implements GraphWriter {
+    private Kryo kryo;
+    private final KryoMapper.HeaderWriter headerWriter;
+    private static final UUID delimiter = UUID.fromString("2DEE3ABF-9963-4546-A578-C1C48690D7F7");
+    public static final byte[] DELIMITER = new byte[16];
+
+    static {
+        final ByteBuffer bb = ByteBuffer.wrap(DELIMITER);
+        bb.putLong(delimiter.getMostSignificantBits());
+        bb.putLong(delimiter.getLeastSignificantBits());
+    }
+
+    private KryoWriter(final KryoMapper kryoMapper) {
+        this.kryo = kryoMapper.createMapper();
+        this.headerWriter = kryoMapper.getHeaderWriter();
+    }
+
+    @Override
+    public void writeGraph(final OutputStream outputStream, final Graph g) throws IOException {
+        final Output output = new Output(outputStream);
+        this.headerWriter.write(kryo, output);
+
+        final boolean supportsGraphMemory = g.features().graph().variables().supportsVariables();
+        output.writeBoolean(supportsGraphMemory);
+        if (supportsGraphMemory)
+            kryo.writeObject(output, new HashMap(g.variables().asMap()));
+
+        final Iterator<Vertex> vertices = g.iterators().vertexIterator();
+        final boolean hasSomeVertices = vertices.hasNext();
+        output.writeBoolean(hasSomeVertices);
+        while (vertices.hasNext()) {
+            final Vertex v = vertices.next();
+            writeVertexToOutput(output, v, Direction.OUT);
+        }
+
+        output.flush();
+    }
+
+    @Override
+    public void writeVertex(final OutputStream outputStream, final Vertex v, final Direction direction) throws IOException {
+        final Output output = new Output(outputStream);
+        this.headerWriter.write(kryo, output);
+        writeVertexToOutput(output, v, direction);
+        output.flush();
+    }
+
+    @Override
+    public void writeVertex(final OutputStream outputStream, final Vertex v) throws IOException {
+        final Output output = new Output(outputStream);
+        this.headerWriter.write(kryo, output);
+        writeVertexWithNoEdgesToOutput(output, v);
+        output.flush();
+    }
+
+    @Override
+    public void writeEdge(final OutputStream outputStream, final Edge e) throws IOException {
+        final Output output = new Output(outputStream);
+        this.headerWriter.write(kryo, output);
+        kryo.writeClassAndObject(output, DetachedFactory.detach(e, true));
+        output.flush();
+    }
+
+    private void writeEdgeToOutput(final Output output, final Edge e) {
+        this.writeElement(output, e, null);
+    }
+
+    private void writeVertexWithNoEdgesToOutput(final Output output, final Vertex v) {
+        writeElement(output, v, null);
+    }
+
+    private void writeVertexToOutput(final Output output, final Vertex v, final Direction direction) {
+        this.writeElement(output, v, direction);
+    }
+
+    private void writeElement(final Output output, final Element e, final Direction direction) {
+        kryo.writeClassAndObject(output, e);
+
+        if (e instanceof Vertex) {
+            output.writeBoolean(direction != null);
+            if (direction != null) {
+                final Vertex v = (Vertex) e;
+                kryo.writeObject(output, direction);
+                if (direction == Direction.BOTH || direction == Direction.OUT)
+                    writeDirectionalEdges(output, Direction.OUT, v.iterators().edgeIterator(Direction.OUT));
+
+                if (direction == Direction.BOTH || direction == Direction.IN)
+                    writeDirectionalEdges(output, Direction.IN, v.iterators().edgeIterator(Direction.IN));
+            }
+
+            kryo.writeClassAndObject(output, VertexTerminator.INSTANCE);
+        }
+    }
+
+    private void writeDirectionalEdges(final Output output, final Direction d, final Iterator<Edge> vertexEdges) {
+        final boolean hasEdges = vertexEdges.hasNext();
+        kryo.writeObject(output, d);
+        output.writeBoolean(hasEdges);
+
+        while (vertexEdges.hasNext()) {
+            final Edge edgeToWrite = vertexEdges.next();
+            writeEdgeToOutput(output, edgeToWrite);
+        }
+
+        if (hasEdges)
+            kryo.writeClassAndObject(output, EdgeTerminator.INSTANCE);
+    }
+
+    public static Builder build() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        /**
+         * Always creates the most current version available.
+         */
+        private KryoMapper kryoMapper = KryoMapper.build().create();
+
+        private Builder() {
+        }
+
+        /**
+         * Supply a mapper {@link KryoMapper} instance to use as the serializer for the {@code KryoWriter}.
+         */
+        public Builder mapper(final KryoMapper kryoMapper) {
+            this.kryoMapper = kryoMapper;
+            return this;
+        }
+
+        /**
+         * Create the {@code KryoWriter}.
+         */
+        public KryoWriter create() {
+            return new KryoWriter(this.kryoMapper);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/URISerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/URISerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/URISerializer.java
new file mode 100644
index 0000000..fd8a59d
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/URISerializer.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
+import java.net.URI;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class URISerializer extends Serializer<URI> {
+
+    public URISerializer() {
+        setImmutable(true);
+    }
+
+    @Override
+    public void write(final Kryo kryo, final Output output, final URI uri) {
+        output.writeString(uri.toString());
+    }
+
+    @Override
+    public URI read(final Kryo kryo, final Input input, final Class<URI> uriClass) {
+        return URI.create(input.readString());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/UUIDSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/UUIDSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/UUIDSerializer.java
new file mode 100644
index 0000000..f43e503
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/kryo/UUIDSerializer.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.tinkerpop.gremlin.structure.io.kryo;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
+import java.util.UUID;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class UUIDSerializer extends Serializer<UUID> {
+    public UUIDSerializer() {
+        setImmutable(true);
+    }
+
+    @Override
+    public void write(final Kryo kryo, final Output output, final UUID uuid) {
+        output.writeLong(uuid.getMostSignificantBits());
+        output.writeLong(uuid.getLeastSignificantBits());
+    }
+
+    @Override
+    public UUID read(final Kryo kryo, final Input input, final Class<UUID> uuidClass) {
+        return new UUID(input.readLong(), input.readLong());
+    }
+}