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/04/29 19:49:41 UTC

incubator-tinkerpop git commit: Got normalization back into GraphSON serialization.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master 73221e62b -> 3b361cc33


Got normalization back into GraphSON serialization.

This capability was lost momentarily when the intermediary conversion to HashMaps prior to json serialization was in place.  With that gone, there needed to be some checks for the normalization flag with sorting behavior as needed.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/3b361cc3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/3b361cc3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/3b361cc3

Branch: refs/heads/master
Commit: 3b361cc3398be909c98cba783ea843584261ee5f
Parents: 73221e6
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Apr 29 13:47:38 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Apr 29 13:47:38 2015 -0400

----------------------------------------------------------------------
 data/tinkerpop-classic-normalized.json          |  6 ---
 data/tinkerpop-modern-normalized.json           |  6 ---
 .../structure/io/graphson/GraphSONModule.java   | 11 +++--
 .../io/graphson/GraphSONSerializers.java        | 51 +++++++++++++-------
 .../util/star/StarGraphGraphSONSerializer.java  | 49 ++++++++++++++-----
 .../gremlin/util/iterator/IteratorUtils.java    |  8 +++
 .../graphson/tinkerpop-classic-normalized.json  | 12 ++---
 .../graphson/tinkerpop-modern-normalized.json   | 12 ++---
 8 files changed, 96 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/data/tinkerpop-classic-normalized.json
----------------------------------------------------------------------
diff --git a/data/tinkerpop-classic-normalized.json b/data/tinkerpop-classic-normalized.json
deleted file mode 100644
index 5ccfe05..0000000
--- a/data/tinkerpop-classic-normalized.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{"id":1,"label":"vertex","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":0,"value":"marko"}],"age":[{"id":2,"value":29}]}}
-{"id":2,"label":"vertex","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"name":[{"id":3,"value":"vadas"}],"age":[{"id":4,"value":27}]}}
-{"id":3,"label":"vertex","inE":{"created":[{"id":9,"outV":1,"properties":{"weight":0.4}},{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":5,"value":"lop"}],"lang":[{"id":6,"value":"java"}]}}
-{"id":4,"label":"vertex","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"name":[{"id":7,"value":"josh"}],"age":[{"id":8,"value":32}]}}
-{"id":5,"label":"vertex","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":9,"value":"ripple"}],"lang":[{"id":10,"value":"java"}]}}
-{"id":6,"label":"vertex","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":11,"value":"peter"}],"age":[{"id":12,"value":35}]}}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/data/tinkerpop-modern-normalized.json
----------------------------------------------------------------------
diff --git a/data/tinkerpop-modern-normalized.json b/data/tinkerpop-modern-normalized.json
deleted file mode 100644
index 18c265d..0000000
--- a/data/tinkerpop-modern-normalized.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{"id":1,"label":"person","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":0,"value":"marko"}],"age":[{"id":1,"value":29}]}}
-{"id":2,"label":"person","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"name":[{"id":2,"value":"vadas"}],"age":[{"id":3,"value":27}]}}
-{"id":3,"label":"software","inE":{"created":[{"id":9,"outV":1,"properties":{"weight":0.4}},{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":4,"value":"lop"}],"lang":[{"id":5,"value":"java"}]}}
-{"id":4,"label":"person","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"name":[{"id":6,"value":"josh"}],"age":[{"id":7,"value":32}]}}
-{"id":5,"label":"software","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":8,"value":"ripple"}],"lang":[{"id":9,"value":"java"}]}}
-{"id":6,"label":"person","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":10,"value":"peter"}],"age":[{"id":11,"value":35}]}}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index 0a7f0f8..39fe40e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -27,20 +27,21 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.star.StarGraphGraphSONSerializer;
 
-
 /**
+ * The set of serializers that handle the core graph interfaces.
+ *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class GraphSONModule extends SimpleModule {
 
     public GraphSONModule(final boolean normalize) {
         super("graphson");
-        addSerializer(Edge.class, new GraphSONSerializers.EdgeJacksonSerializer());
-        addSerializer(Vertex.class, new GraphSONSerializers.VertexJacksonSerializer());
-        addSerializer(VertexProperty.class, new GraphSONSerializers.VertexPropertyJacksonSerializer());
+        addSerializer(Edge.class, new GraphSONSerializers.EdgeJacksonSerializer(normalize));
+        addSerializer(Vertex.class, new GraphSONSerializers.VertexJacksonSerializer(normalize));
+        addSerializer(VertexProperty.class, new GraphSONSerializers.VertexPropertyJacksonSerializer(normalize));
         addSerializer(Property.class, new GraphSONSerializers.PropertyJacksonSerializer());
         addSerializer(TraversalMetrics.class, new GraphSONSerializers.TraversalMetricsJacksonSerializer());
         addSerializer(Path.class, new GraphSONSerializers.PathJacksonSerializer());
-        addSerializer(StarGraphGraphSONSerializer.DirectionalStarGraph.class, new StarGraphGraphSONSerializer());
+        addSerializer(StarGraphGraphSONSerializer.DirectionalStarGraph.class, new StarGraphGraphSONSerializer(normalize));
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
index d19b30b..126e17f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
@@ -33,7 +33,9 @@ import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.Comparators;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -52,20 +54,23 @@ import java.util.concurrent.TimeUnit;
 class GraphSONSerializers {
     static class VertexPropertyJacksonSerializer extends StdSerializer<VertexProperty> {
 
-        public VertexPropertyJacksonSerializer() {
+        private final boolean normalize;
+
+        public VertexPropertyJacksonSerializer(final boolean normalize) {
             super(VertexProperty.class);
+            this.normalize = normalize;
         }
 
         @Override
         public void serialize(final VertexProperty property, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
                 throws IOException {
-            serializerVertexProperty(property, jsonGenerator, serializerProvider, null);
+            serializerVertexProperty(property, jsonGenerator, serializerProvider, null, normalize);
         }
 
         @Override
         public void serializeWithType(final VertexProperty property, final JsonGenerator jsonGenerator,
                                       final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
-            serializerVertexProperty(property, jsonGenerator, serializerProvider, typeSerializer);
+            serializerVertexProperty(property, jsonGenerator, serializerProvider, typeSerializer, normalize);
         }
 
     }
@@ -99,8 +104,11 @@ class GraphSONSerializers {
 
     static class EdgeJacksonSerializer extends StdSerializer<Edge> {
 
-        public EdgeJacksonSerializer() {
+        private final boolean normalize;
+
+        public EdgeJacksonSerializer(final boolean normalize) {
             super(Edge.class);
+            this.normalize = normalize;
         }
 
 
@@ -115,7 +123,7 @@ class GraphSONSerializers {
             ser(edge, jsonGenerator, serializerProvider, typeSerializer);
         }
 
-        private static void ser(final Edge edge, final JsonGenerator jsonGenerator,
+        private void ser(final Edge edge, final JsonGenerator jsonGenerator,
                                 final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
             jsonGenerator.writeStartObject();
             if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
@@ -131,10 +139,11 @@ class GraphSONSerializers {
             jsonGenerator.writeEndObject();
         }
 
-        private static void writeProperties(final Edge edge, final JsonGenerator jsonGenerator,
+        private void writeProperties(final Edge edge, final JsonGenerator jsonGenerator,
                                             final SerializerProvider serializerProvider,
                                             final TypeSerializer typeSerializer) throws IOException {
-            final Iterator<Property<Object>> elementProperties = edge.properties();
+            final Iterator<Property<Object>> elementProperties = normalize ?
+                    IteratorUtils.list(edge.properties(), Comparators.PROPERTY_COMPARATOR).iterator() : edge.properties();
             if (elementProperties.hasNext()) {
                 jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
                 if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
@@ -150,8 +159,11 @@ class GraphSONSerializers {
 
     static class VertexJacksonSerializer extends StdSerializer<Vertex> {
 
-        public VertexJacksonSerializer() {
+        private final boolean normalize;
+
+        public VertexJacksonSerializer(final boolean normalize) {
             super(Vertex.class);
+            this.normalize = normalize;
         }
 
         @Override
@@ -167,7 +179,7 @@ class GraphSONSerializers {
 
         }
 
-        private static void ser(final Vertex vertex, final JsonGenerator jsonGenerator,
+        private void ser(final Vertex vertex, final JsonGenerator jsonGenerator,
                                 final SerializerProvider serializerProvider, final TypeSerializer typeSerializer)
                 throws IOException {
             jsonGenerator.writeStartObject();
@@ -179,9 +191,10 @@ class GraphSONSerializers {
             jsonGenerator.writeEndObject();
         }
 
-        private static void writeProperties(final Vertex vertex, final JsonGenerator jsonGenerator,
+        private void writeProperties(final Vertex vertex, final JsonGenerator jsonGenerator,
                                             final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
-            final Iterator<VertexProperty<Object>> vertexProperties = vertex.properties();
+            final Iterator<VertexProperty<Object>> vertexProperties = normalize ?
+                    IteratorUtils.list(vertex.properties(), Comparators.PROPERTY_COMPARATOR).iterator() : vertex.properties();
             if (vertexProperties.hasNext()) {
                 jsonGenerator.writeArrayFieldStart(GraphSONTokens.PROPERTIES);
                 if (typeSerializer != null) {
@@ -301,41 +314,43 @@ class GraphSONSerializers {
     }
 
     private static void serializerVertexProperty(final VertexProperty property, final JsonGenerator jsonGenerator,
-                                                 final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
+                                                 final SerializerProvider serializerProvider,
+                                                 final TypeSerializer typeSerializer, final boolean normalize) throws IOException {
         jsonGenerator.writeStartObject();
         if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
         GraphSONUtil.writeWithType(GraphSONTokens.ID, property.id(), jsonGenerator, serializerProvider, typeSerializer);
         GraphSONUtil.writeWithType(GraphSONTokens.VALUE, property.value(), jsonGenerator, serializerProvider, typeSerializer);
         jsonGenerator.writeStringField(GraphSONTokens.LABEL, property.label());
-        tryWriteMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer);
+        tryWriteMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer, normalize);
         jsonGenerator.writeEndObject();
     }
 
     private static void tryWriteMetaProperties(final VertexProperty property, final JsonGenerator jsonGenerator,
                                                final SerializerProvider serializerProvider,
-                                               final TypeSerializer typeSerializer) throws IOException {
+                                               final TypeSerializer typeSerializer, final boolean normalize) throws IOException {
         // when "detached" you can't check features of the graph it detached from so it has to be
         // treated differently from a regular VertexProperty implementation.
         if (property instanceof DetachedVertexProperty) {
             // only write meta properties key if they exist
             if (property.properties().hasNext()) {
-                writeMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer);
+                writeMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer, normalize);
             }
         } else {
             // still attached - so we can check the features to see if it's worth even trying to write the
             // meta properties key
             if (property.graph().features().vertex().supportsMetaProperties() && property.properties().hasNext()) {
-                writeMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer);
+                writeMetaProperties(property, jsonGenerator, serializerProvider, typeSerializer, normalize);
             }
         }
     }
 
     private static void writeMetaProperties(final VertexProperty property, final JsonGenerator jsonGenerator,
                                             final SerializerProvider serializerProvider,
-                                            final TypeSerializer typeSerializer) throws IOException {
+                                            final TypeSerializer typeSerializer, final boolean normalize) throws IOException {
         jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
         if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
-        final Iterator<Property<Object>> metaProperties = property.properties();
+        final Iterator<Property<Object>> metaProperties = normalize ?
+                IteratorUtils.list(( Iterator<Property<Object>>) property.properties(), Comparators.PROPERTY_COMPARATOR).iterator() : property.properties();
         while (metaProperties.hasNext()) {
             final Property<Object> metaProperty = metaProperties.next();
             GraphSONUtil.writeWithType(metaProperty.key(), metaProperty.value(), jsonGenerator, serializerProvider, typeSerializer);

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphGraphSONSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphGraphSONSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphGraphSONSerializer.java
index e2235d6..a3916c8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphGraphSONSerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraphGraphSONSerializer.java
@@ -33,21 +33,29 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONUtil;
 import org.apache.tinkerpop.gremlin.structure.util.Attachable;
+import org.apache.tinkerpop.gremlin.structure.util.Comparators;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.function.Function;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class StarGraphGraphSONSerializer extends StdSerializer<StarGraphGraphSONSerializer.DirectionalStarGraph> {
-    public StarGraphGraphSONSerializer() {
+    private final boolean normalize;
+    public StarGraphGraphSONSerializer(final boolean normalize) {
         super(DirectionalStarGraph.class);
+        this.normalize = normalize;
     }
 
     @Override
@@ -76,18 +84,24 @@ public class StarGraphGraphSONSerializer extends StdSerializer<StarGraphGraphSON
         if (starGraph.starVertex.vertexProperties != null && !starGraph.starVertex.vertexProperties.isEmpty()) {
             jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
             if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
-            for (final Map.Entry<String, List<VertexProperty>> vp : starGraph.starVertex.vertexProperties.entrySet()) {
-                jsonGenerator.writeArrayFieldStart(vp.getKey());
+            final Set<String> keys = normalize ? new TreeSet<>(starGraph.starVertex.vertexProperties.keySet()) : starGraph.starVertex.vertexProperties.keySet();
+            for (final String k : keys) {
+                final List<VertexProperty> vp = starGraph.starVertex.vertexProperties.get(k);
+                jsonGenerator.writeArrayFieldStart(k);
                 if (typeSerializer != null) {
                     jsonGenerator.writeString(ArrayList.class.getName());
                     jsonGenerator.writeStartArray();
                 }
-                for (final VertexProperty property : vp.getValue()) {
+
+                final List<VertexProperty> vertexProperties = normalize ?sort(vp, Comparators.PROPERTY_COMPARATOR) : vp;
+                for (final VertexProperty property : vertexProperties) {
                     jsonGenerator.writeStartObject();
                     if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
                     GraphSONUtil.writeWithType(GraphSONTokens.ID, property.id(), jsonGenerator, serializerProvider, typeSerializer);
                     GraphSONUtil.writeWithType(GraphSONTokens.VALUE, property.value(), jsonGenerator, serializerProvider, typeSerializer);
-                    final Iterator<Property<Object>> metaProperties = property.properties();
+
+                    final Iterator<Property> metaProperties = normalize ?
+                            IteratorUtils.list(property.properties(), Comparators.PROPERTY_COMPARATOR).iterator() : property.properties();
                     if (metaProperties.hasNext()) {
                         jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
                         if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
@@ -120,25 +134,31 @@ public class StarGraphGraphSONSerializer extends StdSerializer<StarGraphGraphSON
         if (writeEdges) {
             jsonGenerator.writeObjectFieldStart(direction == Direction.IN ? GraphSONTokens.IN_E : GraphSONTokens.OUT_E);
             if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
-            for (final Map.Entry<String, List<Edge>> edges : starEdges.entrySet()) {
-                jsonGenerator.writeArrayFieldStart(edges.getKey());
+            final Set<String> keys = normalize ? new TreeSet<>(starEdges.keySet()) : starEdges.keySet();
+            for (final String k : keys) {
+                final List<Edge> edges = starEdges.get(k);
+                jsonGenerator.writeArrayFieldStart(k);
                 if (typeSerializer != null) {
                     jsonGenerator.writeString(ArrayList.class.getName());
                     jsonGenerator.writeStartArray();
                 }
-                for (final Edge edge : edges.getValue()) {
+
+                final List<Edge> edgesToWrite = normalize ? sort(edges, Comparators.EDGE_COMPARATOR) : edges;
+                for (final Edge edge : edgesToWrite) {
                     jsonGenerator.writeStartObject();
                     if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
                     GraphSONUtil.writeWithType(GraphSONTokens.ID, edge.id(), jsonGenerator, serializerProvider, typeSerializer);
                     GraphSONUtil.writeWithType(direction.equals(Direction.OUT) ? GraphSONTokens.IN : GraphSONTokens.OUT,
                             direction.equals(Direction.OUT) ? edge.inVertex().id() : edge.outVertex().id(),
                             jsonGenerator, serializerProvider, typeSerializer);
-                    final Iterator<Property<Object>> metaProperties = edge.properties();
-                    if (metaProperties.hasNext()) {
+
+                    final Iterator<Property<Object>> edgeProperties = normalize ?
+                            IteratorUtils.list(edge.properties(), Comparators.PROPERTY_COMPARATOR).iterator() : edge.properties();
+                    if (edgeProperties.hasNext()) {
                         jsonGenerator.writeObjectFieldStart(GraphSONTokens.PROPERTIES);
                         if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
-                        while (metaProperties.hasNext()) {
-                            final Property<Object> meta = metaProperties.next();
+                        while (edgeProperties.hasNext()) {
+                            final Property<Object> meta = edgeProperties.next();
                             GraphSONUtil.writeWithType(meta.key(), meta.value(), jsonGenerator, serializerProvider, typeSerializer);
                         }
                         jsonGenerator.writeEndObject();
@@ -207,6 +227,11 @@ public class StarGraphGraphSONSerializer extends StdSerializer<StarGraphGraphSON
         return starGraph;
     }
 
+    private static <S> List<S> sort(final List<S> listToSort, final Comparator comparator) {
+        Collections.sort(listToSort, comparator);
+        return listToSort;
+    }
+
     public static class DirectionalStarGraph {
         private final Direction direction;
         private final StarGraph starGraphToSerialize;

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
index 801299e..befdd56 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
@@ -19,10 +19,12 @@
 package org.apache.tinkerpop.gremlin.util.iterator;
 
 import org.apache.tinkerpop.gremlin.process.traversal.FastNoSuchElementException;
+import org.apache.tinkerpop.gremlin.structure.util.Comparators;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -77,6 +79,12 @@ public final class IteratorUtils {
         return fill(iterator, new ArrayList<>());
     }
 
+    public static <S> List<S> list(final Iterator<S> iterator, final Comparator comparator) {
+        final List<S> l = list(iterator);
+        Collections.sort(l, comparator);
+        return l;
+    }
+
     public static <S> Set<S> set(final Iterator<S> iterator) {
         return fill(iterator, new HashSet<>());
     }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-classic-normalized.json
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-classic-normalized.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-classic-normalized.json
index 5ccfe05..cb08148 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-classic-normalized.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-classic-normalized.json
@@ -1,6 +1,6 @@
-{"id":1,"label":"vertex","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":0,"value":"marko"}],"age":[{"id":2,"value":29}]}}
-{"id":2,"label":"vertex","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"name":[{"id":3,"value":"vadas"}],"age":[{"id":4,"value":27}]}}
-{"id":3,"label":"vertex","inE":{"created":[{"id":9,"outV":1,"properties":{"weight":0.4}},{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":5,"value":"lop"}],"lang":[{"id":6,"value":"java"}]}}
-{"id":4,"label":"vertex","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"name":[{"id":7,"value":"josh"}],"age":[{"id":8,"value":32}]}}
-{"id":5,"label":"vertex","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":9,"value":"ripple"}],"lang":[{"id":10,"value":"java"}]}}
-{"id":6,"label":"vertex","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":11,"value":"peter"}],"age":[{"id":12,"value":35}]}}
+{"id":1,"label":"vertex","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"age":[{"id":2,"value":29}],"name":[{"id":0,"value":"marko"}]}}
+{"id":2,"label":"vertex","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"age":[{"id":4,"value":27}],"name":[{"id":3,"value":"vadas"}]}}
+{"id":3,"label":"vertex","inE":{"created":[{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}},{"id":9,"outV":1,"properties":{"weight":0.4}}]},"properties":{"lang":[{"id":6,"value":"java"}],"name":[{"id":5,"value":"lop"}]}}
+{"id":4,"label":"vertex","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"age":[{"id":8,"value":32}],"name":[{"id":7,"value":"josh"}]}}
+{"id":5,"label":"vertex","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"lang":[{"id":10,"value":"java"}],"name":[{"id":9,"value":"ripple"}]}}
+{"id":6,"label":"vertex","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"age":[{"id":12,"value":35}],"name":[{"id":11,"value":"peter"}]}}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3b361cc3/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-modern-normalized.json
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-modern-normalized.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-modern-normalized.json
index 18c265d..8c259ea 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-modern-normalized.json
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/tinkerpop-modern-normalized.json
@@ -1,6 +1,6 @@
-{"id":1,"label":"person","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":0,"value":"marko"}],"age":[{"id":1,"value":29}]}}
-{"id":2,"label":"person","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"name":[{"id":2,"value":"vadas"}],"age":[{"id":3,"value":27}]}}
-{"id":3,"label":"software","inE":{"created":[{"id":9,"outV":1,"properties":{"weight":0.4}},{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":4,"value":"lop"}],"lang":[{"id":5,"value":"java"}]}}
-{"id":4,"label":"person","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"name":[{"id":6,"value":"josh"}],"age":[{"id":7,"value":32}]}}
-{"id":5,"label":"software","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"name":[{"id":8,"value":"ripple"}],"lang":[{"id":9,"value":"java"}]}}
-{"id":6,"label":"person","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"name":[{"id":10,"value":"peter"}],"age":[{"id":11,"value":35}]}}
+{"id":1,"label":"person","outE":{"created":[{"id":9,"inV":3,"properties":{"weight":0.4}}],"knows":[{"id":7,"inV":2,"properties":{"weight":0.5}},{"id":8,"inV":4,"properties":{"weight":1.0}}]},"properties":{"age":[{"id":1,"value":29}],"name":[{"id":0,"value":"marko"}]}}
+{"id":2,"label":"person","inE":{"knows":[{"id":7,"outV":1,"properties":{"weight":0.5}}]},"properties":{"age":[{"id":3,"value":27}],"name":[{"id":2,"value":"vadas"}]}}
+{"id":3,"label":"software","inE":{"created":[{"id":11,"outV":4,"properties":{"weight":0.4}},{"id":12,"outV":6,"properties":{"weight":0.2}},{"id":9,"outV":1,"properties":{"weight":0.4}}]},"properties":{"lang":[{"id":5,"value":"java"}],"name":[{"id":4,"value":"lop"}]}}
+{"id":4,"label":"person","inE":{"knows":[{"id":8,"outV":1,"properties":{"weight":1.0}}]},"outE":{"created":[{"id":10,"inV":5,"properties":{"weight":1.0}},{"id":11,"inV":3,"properties":{"weight":0.4}}]},"properties":{"age":[{"id":7,"value":32}],"name":[{"id":6,"value":"josh"}]}}
+{"id":5,"label":"software","inE":{"created":[{"id":10,"outV":4,"properties":{"weight":1.0}}]},"properties":{"lang":[{"id":9,"value":"java"}],"name":[{"id":8,"value":"ripple"}]}}
+{"id":6,"label":"person","outE":{"created":[{"id":12,"inV":3,"properties":{"weight":0.2}}]},"properties":{"age":[{"id":11,"value":35}],"name":[{"id":10,"value":"peter"}]}}