TINKERPOP-2967 Added untyped GraphSON 3.0
Essentialy exposes untyped GraphSON 3.0 which is basically the untyped GraphSON 1.0. Had to refactor the GraphSONModule slightly to handle this by passing TypeInfo through it to the serializers which needed to know whether they were serializing that way or not.
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d3aeb70..76abc99 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -54,6 +54,7 @@
* Renamed all `MessageSerializer` implementations that used the "d0" suffix to drop that convention.
* Removed deprecated `GraphSONMessageSerializerGremlinV1d0` as this is now `GraphSONMessageSerializerV1` to be consistent with other naming.
* Added `GraphSONUntypedMessageSerializerV1` which was formerly `GraphSONMessageSerializerV1d0` to be consistent with other naming.
+* Added `GraphSONUntypedMessageSerializerV3` which essentially matches the format of GraphSON 1.0 in its untyped form.
* Bumped Groovy to 4.0.9.
* Bumped GMavenPlus to 2.1.0.
* Bumped Spark to 3.3.2.
diff --git a/docs/src/dev/io/graphson.asciidoc b/docs/src/dev/io/graphson.asciidoc
index 29dcfb6..1aa2bc1 100644
--- a/docs/src/dev/io/graphson.asciidoc
+++ b/docs/src/dev/io/graphson.asciidoc
@@ -22,14 +22,14 @@
import java.time.*
mapper = GraphSONMapper.build().
addRegistry(TinkerIoRegistry.instance()).
- addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV1d0.GremlinServerModule()).
+ addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV1.GremlinServerModule()).
version(GraphSONVersion.V1_0).create().createMapper()
graph = TinkerFactory.createTheCrew()
g = graph.traversal()
new File("io-output/test-case-data/graphson/").mkdirs()
-toJson = { o, type, comment = "", suffix = "v1d0" ->
+toJson = { o, type, comment = "", suffix = "v1" ->
println "Writing ${type}"
def jsonSample = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o)
@@ -50,7 +50,7 @@
}
-file = new File("io-output/out-graphson-1d0.txt")
+file = new File("io-output/out-graphson-1.txt")
file.withWriter { writer ->
writer.write("=== Graph Structure\n\n")
@@ -104,260 +104,260 @@
}
mapper = GraphSONMapper.build().
- addRegistry(TinkerIoRegistryV2d0.instance()).
+ addRegistry(TinkerIoRegistryV2.instance()).
typeInfo(TypeInfo.PARTIAL_TYPES).
- addCustomModule(GraphSONXModuleV2d0.build().create(false)).
- addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV2d0.GremlinServerModule()).
+ addCustomModule(GraphSONXModuleV2.build()).
+ addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV2.GremlinServerModule()).
version(GraphSONVersion.V2_0).create().createMapper()
-file = new File("io-output/out-graphson-2d0-partial.txt")
+file = new File("io-output/out-graphson-2-partial.txt")
file.withWriter { writer ->
writer.write("=== Core\n\n")
- writer.write(toJson(File, "Class", "", "v2d0-partial"))
- writer.write(toJson(new Date(1481750076295L), "Date", "", "v2d0-partial"))
- writer.write(toJson(100.00d, "Double", "", "v2d0-partial"))
- writer.write(toJson(100.00f, "Float", "", "v2d0-partial"))
- writer.write(toJson(100, "Integer", "", "v2d0-partial"))
- writer.write(toJson(100L, "Long", "", "v2d0-partial"))
- writer.write(toJson(new java.sql.Timestamp(1481750076295L), "Timestamp", "", "v2d0-partial"))
- writer.write(toJson(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786"), "UUID", "", "v2d0-partial"))
+ writer.write(toJson(File, "Class", "", "v2-partial"))
+ writer.write(toJson(new Date(1481750076295L), "Date", "", "v2-partial"))
+ writer.write(toJson(100.00d, "Double", "", "v2-partial"))
+ writer.write(toJson(100.00f, "Float", "", "v2-partial"))
+ writer.write(toJson(100, "Integer", "", "v2-partial"))
+ writer.write(toJson(100L, "Long", "", "v2-partial"))
+ writer.write(toJson(new java.sql.Timestamp(1481750076295L), "Timestamp", "", "v2-partial"))
+ writer.write(toJson(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786"), "UUID", "", "v2-partial"))
writer.write("\n")
writer.write("=== Graph Structure\n\n")
- writer.write(toJson(graph.edges().next(), "Edge", "", "v2d0-partial"))
- writer.write(toJson(g.V().out().out().path().next(), "Path", "", "v2d0-partial"))
- writer.write(toJson(graph.edges().next().properties().next(), "Property", "", "v2d0-partial"))
- writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph", "", "v2d0-partial"))
- writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.", "v2d0-partial"))
- writer.write(toJson(g.V().out().out().tree().next(), "Tree", "", "v2d0-partial"))
- writer.write(toJson(graph.vertices().next(), "Vertex", "", "v2d0-partial"))
- writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty", "", "v2d0-partial"))
+ writer.write(toJson(graph.edges().next(), "Edge", "", "v2-partial"))
+ writer.write(toJson(g.V().out().out().path().next(), "Path", "", "v2-partial"))
+ writer.write(toJson(graph.edges().next().properties().next(), "Property", "", "v2-partial"))
+ writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph", "", "v2-partial"))
+ writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.", "v2-partial"))
+ writer.write(toJson(g.V().out().out().tree().next(), "Tree", "", "v2-partial"))
+ writer.write(toJson(graph.vertices().next(), "Vertex", "", "v2-partial"))
+ writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty", "", "v2-partial"))
writer.write("\n")
writer.write("=== Graph Process\n\n")
- writer.write(toJson(SackFunctions.Barrier.normSack, "Barrier", "", "v2d0-partial"))
- writer.write(toJson(new Bytecode.Binding("x", 1), "Binding", "A \"Binding\" refers to a `Bytecode.Binding`.", "v2d0-partial"))
- writer.write(toJson(g.V().hasLabel('person').out().in().tree(), "Bytecode", "The following `Bytecode` example represents the traversal of `g.V().hasLabel('person').out().in().tree()`. Obviously the serialized `Bytecode` would be quite different for the endless variations of commands that could be used together in the Gremlin language.", "v2d0-partial"))
- writer.write(toJson(VertexProperty.Cardinality.list, "Cardinality", "", "v2d0-partial"))
- writer.write(toJson(Column.keys, "Column", "", "v2d0-partial"))
- writer.write(toJson(Direction.OUT, "Direction", "", "v2d0-partial"))
- writer.write(toJson(Operator.sum, "Operator", "", "v2d0-partial"))
- writer.write(toJson(Order.shuffle, "Order", "", "v2d0-partial"))
- writer.write(toJson(org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.any, "Pick", "", "v2d0-partial"))
- writer.write(toJson(Pop.all, "Pop", "", "v2d0-partial"))
- writer.write(toJson(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", "v2d0-partial"))
+ writer.write(toJson(SackFunctions.Barrier.normSack, "Barrier", "", "v2-partial"))
+ writer.write(toJson(new Bytecode.Binding("x", 1), "Binding", "A \"Binding\" refers to a `Bytecode.Binding`.", "v2-partial"))
+ writer.write(toJson(g.V().hasLabel('person').out().in().tree(), "Bytecode", "The following `Bytecode` example represents the traversal of `g.V().hasLabel('person').out().in().tree()`. Obviously the serialized `Bytecode` would be quite different for the endless variations of commands that could be used together in the Gremlin language.", "v2-partial"))
+ writer.write(toJson(VertexProperty.Cardinality.list, "Cardinality", "", "v2-partial"))
+ writer.write(toJson(Column.keys, "Column", "", "v2-partial"))
+ writer.write(toJson(Direction.OUT, "Direction", "", "v2-partial"))
+ writer.write(toJson(Operator.sum, "Operator", "", "v2-partial"))
+ writer.write(toJson(Order.shuffle, "Order", "", "v2-partial"))
+ writer.write(toJson(org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.any, "Pick", "", "v2-partial"))
+ writer.write(toJson(Pop.all, "Pop", "", "v2-partial"))
+ writer.write(toJson(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", "v2-partial"))
tm = g.V().hasLabel('person').out().out().tree().profile().next()
metrics = new org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics(tm.getMetrics(0));
metrics.addNested(new org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics(tm.getMetrics(1)));
- writer.write(toJson(metrics, "Metrics", "", "v2d0-partial"))
- writer.write(toJson(P.gt(0), "P", "`P` expects a single value of a `List` of values. There is special handling for `List` values when it comes to `within`, `without`, `inside`, `outside` and `between`. For `inside`, `outside` and `between`, the expectation is that the collection contain two objects (the rest will be ignored) and those two objects become the arguments to those methods. For `within` and `without`, these methods will accept an arbitrary number of objects in the collection.", "v2d0-partial"))
- writer.write(toJson(P.within(1), "P within", "Please see <<p,P>> for additional information on `within`.", "v2d0-partial"))
- writer.write(toJson(P.without(1,2), "P without", "Please see <<p,P>> for additional information on `within`.", "v2d0-partial"))
- writer.write(toJson(P.gt(0).and(P.lt(10)), "P and", "", "v2d0-partial"))
- writer.write(toJson(P.gt(0).or(P.within(-1, -10, -100)), "P or", "", "v2d0-partial"))
- writer.write(toJson(Scope.local, "Scope", "", "v2d0-partial"))
- writer.write(toJson(T.label, "T", "", "v2d0-partial"))
- writer.write(toJson(g.V().hasLabel('person').out().out().tree().profile().next(), "TraversalMetrics", "", "v2d0-partial"))
- writer.write(toJson(g.V().hasLabel('person').nextTraverser(), "Traverser", "", "v2d0-partial"))
+ writer.write(toJson(metrics, "Metrics", "", "v2-partial"))
+ writer.write(toJson(P.gt(0), "P", "`P` expects a single value of a `List` of values. There is special handling for `List` values when it comes to `within`, `without`, `inside`, `outside` and `between`. For `inside`, `outside` and `between`, the expectation is that the collection contain two objects (the rest will be ignored) and those two objects become the arguments to those methods. For `within` and `without`, these methods will accept an arbitrary number of objects in the collection.", "v2-partial"))
+ writer.write(toJson(P.within(1), "P within", "Please see <<p,P>> for additional information on `within`.", "v2-partial"))
+ writer.write(toJson(P.without(1,2), "P without", "Please see <<p,P>> for additional information on `within`.", "v2-partial"))
+ writer.write(toJson(P.gt(0).and(P.lt(10)), "P and", "", "v2-partial"))
+ writer.write(toJson(P.gt(0).or(P.within(-1, -10, -100)), "P or", "", "v2-partial"))
+ writer.write(toJson(Scope.local, "Scope", "", "v2-partial"))
+ writer.write(toJson(T.label, "T", "", "v2-partial"))
+ writer.write(toJson(g.V().hasLabel('person').out().out().tree().profile().next(), "TraversalMetrics", "", "v2-partial"))
+ writer.write(toJson(g.V().hasLabel('person').nextTraverser(), "Traverser", "", "v2-partial"))
writer.write("\n")
writer.write("=== RequestMessage\n\n")
msg = RequestMessage.build("authentication").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==").create()
- writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.", "v2d0-partial"))
+ writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.", "v2-partial"))
msg = RequestMessage.build("eval").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.", "v2d0-partial"))
+ writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.", "v2-partial"))
msg = RequestMessage.build("eval").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"], "session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2d0-partial"))
+ writer.write(toJson(msg, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2-partial"))
msg = RequestMessage.build("close").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session.", "v2d0-partial"))
+ writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session.", "v2-partial"))
msg = RequestMessage.build("eval").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy").create()
- writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.", "v2d0-partial"))
+ writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.", "v2-partial"))
msg = RequestMessage.build("eval").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"]).create()
- writer.write(toJson(msg, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2d0-partial"))
+ writer.write(toJson(msg, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2-partial"))
writer.write("\n")
writer.write("=== ResponseMessage\n\n")
msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
code(org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode.AUTHENTICATE).create()
- writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges may be requested in some cases, but no in the default provided by Gremlin Server).", "v2d0-partial"))
+ writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges may be requested in some cases, but no in the default provided by Gremlin Server).", "v2-partial"))
msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
code(org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode.SUCCESS).
result(Arrays.asList(graph.vertices().next())).create()
- writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.", "v2d0-partial"))
+ writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.", "v2-partial"))
writer.write("\n")
writer.write("=== Extended\n\n")
- writer.write("""Note that the "extended" types require the addition of the separate `GraphSONXModuleV2d0` module as follows:\n
+ writer.write("""Note that the "extended" types require the addition of the separate `GraphSONXModuleV2` module as follows:\n
[source,java]
----
mapper = GraphSONMapper.build().
typeInfo(TypeInfo.PARTIAL_TYPES).
- addCustomModule(GraphSONXModuleV2d0.build().create(false)).
+ addCustomModule(GraphSONXModuleV2.build()).
version(GraphSONVersion.V2_0).create().createMapper()
----\n
""")
- writer.write(toJson(new java.math.BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal", "", "v2d0-partial"))
- writer.write(toJson(new java.math.BigInteger("123456789987654321123456789987654321"), "BigInteger", "", "v2d0-partial"))
- writer.write(toJson(new Byte("1"), "Byte", "", "v2d0-partial"))
- writer.write(toJson(java.nio.ByteBuffer.wrap("some bytes for you".getBytes()), "ByteBuffer", "", "v2d0-partial"))
- writer.write(toJson("x".charAt(0), "Char", "", "v2d0-partial"))
- writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days.", "v2d0-partial"))
- writer.write(toJson(java.net.InetAddress.getByName("localhost"), "InetAddress", "", "v2d0-partial"))
- writer.write(toJson(Instant.parse("2016-12-14T16:39:19.349Z"), "Instant", "", "v2d0-partial"))
- writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate", "", "v2d0-partial"))
- writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime", "", "v2d0-partial"))
- writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime", "", "v2d0-partial"))
- writer.write(toJson(MonthDay.of(1, 1), "MonthDay", "", "v2d0-partial"))
- writer.write(toJson(OffsetDateTime.parse("2007-12-03T10:15:30+01:00"), "OffsetDateTime", "", "v2d0-partial"))
- writer.write(toJson(OffsetTime.parse("10:15:30+01:00"), "OffsetTime", "", "v2d0-partial"))
- writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days.", "v2d0-partial"))
- writer.write(toJson(new Short("100"), "Short", "", "v2d0-partial"))
- writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\".", "v2d0-partial"))
- writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\"", "v2d0-partial"))
- writer.write(toJson(ZonedDateTime.of(2016, 12, 23, 12, 12, 24, 36, ZoneId.of("GMT+2")), "ZonedDateTime", "", "v2d0-partial"))
- writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds.", "v2d0-partial"))
+ writer.write(toJson(new java.math.BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal", "", "v2-partial"))
+ writer.write(toJson(new java.math.BigInteger("123456789987654321123456789987654321"), "BigInteger", "", "v2-partial"))
+ writer.write(toJson(new Byte("1"), "Byte", "", "v2-partial"))
+ writer.write(toJson(java.nio.ByteBuffer.wrap("some bytes for you".getBytes()), "ByteBuffer", "", "v2-partial"))
+ writer.write(toJson("x".charAt(0), "Char", "", "v2-partial"))
+ writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days.", "v2-partial"))
+ writer.write(toJson(java.net.InetAddress.getByName("localhost"), "InetAddress", "", "v2-partial"))
+ writer.write(toJson(Instant.parse("2016-12-14T16:39:19.349Z"), "Instant", "", "v2-partial"))
+ writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate", "", "v2-partial"))
+ writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime", "", "v2-partial"))
+ writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime", "", "v2-partial"))
+ writer.write(toJson(MonthDay.of(1, 1), "MonthDay", "", "v2-partial"))
+ writer.write(toJson(OffsetDateTime.parse("2007-12-03T10:15:30+01:00"), "OffsetDateTime", "", "v2-partial"))
+ writer.write(toJson(OffsetTime.parse("10:15:30+01:00"), "OffsetTime", "", "v2-partial"))
+ writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days.", "v2-partial"))
+ writer.write(toJson(new Short("100"), "Short", "", "v2-partial"))
+ writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\".", "v2-partial"))
+ writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\"", "v2-partial"))
+ writer.write(toJson(ZonedDateTime.of(2016, 12, 23, 12, 12, 24, 36, ZoneId.of("GMT+2")), "ZonedDateTime", "", "v2-partial"))
+ writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds.", "v2-partial"))
}
mapper = GraphSONMapper.build().
- addRegistry(TinkerIoRegistryV2d0.instance()).
+ addRegistry(TinkerIoRegistryV2.instance()).
typeInfo(TypeInfo.NO_TYPES).
- addCustomModule(GraphSONXModuleV2d0.build().create(false)).
- addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV2d0.GremlinServerModule()).
+ addCustomModule(GraphSONXModuleV2.build()).
+ addCustomModule(new org.apache.tinkerpop.gremlin.util.ser.AbstractGraphSONMessageSerializerV2.GremlinServerModule()).
version(GraphSONVersion.V2_0).create().createMapper()
-file = new File("io-output/out-graphson-2d0-no-types.txt")
+file = new File("io-output/out-graphson-2-no-types.txt")
file.withWriter { writer ->
writer.write("=== Core\n\n")
- writer.write(toJson(File, "Class", "", "v2d0-no-types"))
- writer.write(toJson(new Date(1481750076295L), "Date", "", "v2d0-no-types"))
- writer.write(toJson(100.00d, "Double", "", "v2d0-no-types"))
- writer.write(toJson(100.00f, "Float", "", "v2d0-no-types"))
- writer.write(toJson(100, "Integer", "", "v2d0-no-types"))
- writer.write(toJson(100L, "Long", "", "v2d0-no-types"))
- writer.write(toJson(new java.sql.Timestamp(1481750076295L), "Timestamp", "", "v2d0-no-types"))
- writer.write(toJson(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786"), "UUID", "", "v2d0-no-types"))
+ writer.write(toJson(File, "Class", "", "v2-no-types"))
+ writer.write(toJson(new Date(1481750076295L), "Date", "", "v2-no-types"))
+ writer.write(toJson(100.00d, "Double", "", "v2-no-types"))
+ writer.write(toJson(100.00f, "Float", "", "v2-no-types"))
+ writer.write(toJson(100, "Integer", "", "v2-no-types"))
+ writer.write(toJson(100L, "Long", "", "v2-no-types"))
+ writer.write(toJson(new java.sql.Timestamp(1481750076295L), "Timestamp", "", "v2-no-types"))
+ writer.write(toJson(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786"), "UUID", "", "v2-no-types"))
writer.write("\n")
writer.write("=== Graph Structure\n\n")
- writer.write(toJson(graph.edges().next(), "Edge", "", "v2d0-no-types"))
- writer.write(toJson(g.V().out().out().path().next(), "Path", "", "v2d0-no-types"))
- writer.write(toJson(graph.edges().next().properties().next(), "Property", "", "v2d0-no-types"))
- writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph", "", "v2d0-no-types"))
- writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.", "v2d0-no-types"))
- writer.write(toJson(g.V().out().out().tree().next(), "Tree", "", "v2d0-no-types"))
- writer.write(toJson(graph.vertices().next(), "Vertex", "", "v2d0-no-types"))
- writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty", "", "v2d0-no-types"))
+ writer.write(toJson(graph.edges().next(), "Edge", "", "v2-no-types"))
+ writer.write(toJson(g.V().out().out().path().next(), "Path", "", "v2-no-types"))
+ writer.write(toJson(graph.edges().next().properties().next(), "Property", "", "v2-no-types"))
+ writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph", "", "v2-no-types"))
+ writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.", "v2-no-types"))
+ writer.write(toJson(g.V().out().out().tree().next(), "Tree", "", "v2-no-types"))
+ writer.write(toJson(graph.vertices().next(), "Vertex", "", "v2-no-types"))
+ writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty", "", "v2-no-types"))
writer.write("\n")
writer.write("=== Graph Process\n\n")
- writer.write(toJson(SackFunctions.Barrier.normSack, "Barrier", "", "v2d0-no-types"))
- writer.write(toJson(new Bytecode.Binding("x", 1), "Binding", "A \"Binding\" refers to a `Bytecode.Binding`.", "v2d0-no-types"))
- writer.write(toJson(g.V().hasLabel('person').out().in().tree(), "Bytecode", "The following `Bytecode` example represents the traversal of `g.V().hasLabel('person').out().in().tree()`. Obviously the serialized `Bytecode` would be quite different for the endless variations of commands that could be used together in the Gremlin language.", "v2d0-no-types"))
- writer.write(toJson(VertexProperty.Cardinality.list, "Cardinality", "", "v2d0-no-types"))
- writer.write(toJson(Column.keys, "Column", "", "v2d0-no-types"))
- writer.write(toJson(Direction.OUT, "Direction", "", "v2d0-no-types"))
- writer.write(toJson(Operator.sum, "Operator", "", "v2d0-no-types"))
- writer.write(toJson(Order.shuffle, "Order", "", "v2d0-no-types"))
- writer.write(toJson(Pop.all, "Pop", "", "v2d0-no-types"))
- writer.write(toJson(org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.any, "Pick", "", "v2d0-no-types"))
- writer.write(toJson(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", "v2d0-no-types"))
+ writer.write(toJson(SackFunctions.Barrier.normSack, "Barrier", "", "v2-no-types"))
+ writer.write(toJson(new Bytecode.Binding("x", 1), "Binding", "A \"Binding\" refers to a `Bytecode.Binding`.", "v2-no-types"))
+ writer.write(toJson(g.V().hasLabel('person').out().in().tree(), "Bytecode", "The following `Bytecode` example represents the traversal of `g.V().hasLabel('person').out().in().tree()`. Obviously the serialized `Bytecode` would be quite different for the endless variations of commands that could be used together in the Gremlin language.", "v2-no-types"))
+ writer.write(toJson(VertexProperty.Cardinality.list, "Cardinality", "", "v2-no-types"))
+ writer.write(toJson(Column.keys, "Column", "", "v2-no-types"))
+ writer.write(toJson(Direction.OUT, "Direction", "", "v2-no-types"))
+ writer.write(toJson(Operator.sum, "Operator", "", "v2-no-types"))
+ writer.write(toJson(Order.shuffle, "Order", "", "v2-no-types"))
+ writer.write(toJson(Pop.all, "Pop", "", "v2-no-types"))
+ writer.write(toJson(org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.any, "Pick", "", "v2-no-types"))
+ writer.write(toJson(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", "v2-no-types"))
tm = g.V().hasLabel('person').out().out().tree().profile().next()
metrics = new org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics(tm.getMetrics(0));
metrics.addNested(new org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics(tm.getMetrics(1)));
- writer.write(toJson(metrics, "Metrics", "", "v2d0-no-types"))
- writer.write(toJson(P.gt(0), "P", "", "v2d0-no-types"))
- writer.write(toJson(P.within(1), "P within", "v2d0-no-types"))
- writer.write(toJson(P.without(1,2), "P without", "v2d0-no-types"))
- writer.write(toJson(P.gt(0).and(P.lt(10)), "P and", "", "v2d0-no-types"))
- writer.write(toJson(P.gt(0).or(P.within(-1, -10, -100)), "P or", "", "v2d0-no-types"))
- writer.write(toJson(Scope.local, "Scope", "", "v2d0-no-types"))
- writer.write(toJson(T.label, "T", "", "v2d0-no-types"))
- writer.write(toJson(g.V().hasLabel('person').out().out().tree().profile().next(), "TraversalMetrics", "", "v2d0-no-types"))
- writer.write(toJson(g.V().hasLabel('person').nextTraverser(), "Traverser", "", "v2d0-no-types"))
+ writer.write(toJson(metrics, "Metrics", "", "v2-no-types"))
+ writer.write(toJson(P.gt(0), "P", "", "v2-no-types"))
+ writer.write(toJson(P.within(1), "P within", "v2-no-types"))
+ writer.write(toJson(P.without(1,2), "P without", "v2-no-types"))
+ writer.write(toJson(P.gt(0).and(P.lt(10)), "P and", "", "v2-no-types"))
+ writer.write(toJson(P.gt(0).or(P.within(-1, -10, -100)), "P or", "", "v2-no-types"))
+ writer.write(toJson(Scope.local, "Scope", "", "v2-no-types"))
+ writer.write(toJson(T.label, "T", "", "v2-no-types"))
+ writer.write(toJson(g.V().hasLabel('person').out().out().tree().profile().next(), "TraversalMetrics", "", "v2-no-types"))
+ writer.write(toJson(g.V().hasLabel('person').nextTraverser(), "Traverser", "", "v2-no-types"))
writer.write("\n")
writer.write("=== RequestMessage\n\n")
msg = RequestMessage.build("authentication").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==").create()
- writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.", "v2d0-no-types"))
+ writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.", "v2-no-types"))
msg = RequestMessage.build("eval").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.", "v2d0-no-types"))
+ writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.", "v2-no-types"))
msg = RequestMessage.build("eval").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"], "session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2d0-no-types"))
+ writer.write(toJson(msg, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2-no-types"))
msg = RequestMessage.build("close").processor("session").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("session", "unique-session-identifier").create()
- writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session.", "v2d0-no-types"))
+ writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session.", "v2-no-types"))
msg = RequestMessage.build("eval").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy").create()
- writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.", "v2d0-no-types"))
+ writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.", "v2-no-types"))
msg = RequestMessage.build("eval").
overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"]).create()
- writer.write(toJson(msg, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2d0-no-types"))
+ writer.write(toJson(msg, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".", "v2-no-types"))
writer.write("\n")
writer.write("=== ResponseMessage\n\n")
msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
code(org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode.AUTHENTICATE).create()
- writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).", "v2d0-no-types"))
+ writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).", "v2-no-types"))
msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
code(org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode.SUCCESS).
result(Arrays.asList(graph.vertices().next())).create()
- writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.", "v2d0-no-types"))
+ writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.", "v2-no-types"))
writer.write("\n")
writer.write("=== Extended\n\n")
- writer.write("""Note that the "extended" types require the addition of the separate `GraphSONXModuleV2d0` module as follows:\n
+ writer.write("""Note that the "extended" types require the addition of the separate `GraphSONXModuleV2` module as follows:\n
[source,java]
----
mapper = GraphSONMapper.build().
typeInfo(TypeInfo.NO_TYPES).
- addCustomModule(GraphSONXModuleV2d0.build().create(false)).
+ addCustomModule(GraphSONXModuleV2.build()).
version(GraphSONVersion.V2_0).create().createMapper()
----\n
""")
- writer.write(toJson(new java.math.BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal", "", "v2d0-partial"))
- writer.write(toJson(new java.math.BigInteger("123456789987654321123456789987654321"), "BigInteger", "", "v2d0-partial"))
- writer.write(toJson(new Byte("1"), "Byte", "", "v2d0-partial"))
- writer.write(toJson(java.nio.ByteBuffer.wrap("some bytes for you".getBytes()), "ByteBuffer", "", "v2d0-partial"))
- writer.write(toJson("x".charAt(0), "Char", "", "v2d0-partial"))
- writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days.", "v2d0-partial"))
- writer.write(toJson(java.net.InetAddress.getByName("localhost"), "InetAddress", "", "v2d0-partial"))
- writer.write(toJson(Instant.parse("2016-12-14T16:39:19.349Z"), "Instant", "", "v2d0-partial"))
- writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate", "", "v2d0-partial"))
- writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime", "", "v2d0-partial"))
- writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime", "", "v2d0-partial"))
- writer.write(toJson(MonthDay.of(1, 1), "MonthDay", "", "v2d0-partial"))
- writer.write(toJson(OffsetDateTime.parse("2007-12-03T10:15:30+01:00"), "OffsetDateTime", "", "v2d0-partial"))
- writer.write(toJson(OffsetTime.parse("10:15:30+01:00"), "OffsetTime", "", "v2d0-partial"))
- writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days.", "v2d0-partial"))
- writer.write(toJson(new Short("100"), "Short", "", "v2d0-partial"))
- writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\".", "v2d0-partial"))
- writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\"", "v2d0-partial"))
- writer.write(toJson(ZonedDateTime.of(2016, 12, 23, 12, 12, 24, 36, ZoneId.of("GMT+2")), "ZonedDateTime", "", "v2d0-partial"))
- writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds.", "v2d0-partial"))
+ writer.write(toJson(new java.math.BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal", "", "v2-partial"))
+ writer.write(toJson(new java.math.BigInteger("123456789987654321123456789987654321"), "BigInteger", "", "v2-partial"))
+ writer.write(toJson(new Byte("1"), "Byte", "", "v2-partial"))
+ writer.write(toJson(java.nio.ByteBuffer.wrap("some bytes for you".getBytes()), "ByteBuffer", "", "v2-partial"))
+ writer.write(toJson("x".charAt(0), "Char", "", "v2-partial"))
+ writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days.", "v2-partial"))
+ writer.write(toJson(java.net.InetAddress.getByName("localhost"), "InetAddress", "", "v2-partial"))
+ writer.write(toJson(Instant.parse("2016-12-14T16:39:19.349Z"), "Instant", "", "v2-partial"))
+ writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate", "", "v2-partial"))
+ writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime", "", "v2-partial"))
+ writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime", "", "v2-partial"))
+ writer.write(toJson(MonthDay.of(1, 1), "MonthDay", "", "v2-partial"))
+ writer.write(toJson(OffsetDateTime.parse("2007-12-03T10:15:30+01:00"), "OffsetDateTime", "", "v2-partial"))
+ writer.write(toJson(OffsetTime.parse("10:15:30+01:00"), "OffsetTime", "", "v2-partial"))
+ writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days.", "v2-partial"))
+ writer.write(toJson(new Short("100"), "Short", "", "v2-partial"))
+ writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\".", "v2-partial"))
+ writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\"", "v2-partial"))
+ writer.write(toJson(ZonedDateTime.of(2016, 12, 23, 12, 12, 24, 36, ZoneId.of("GMT+2")), "ZonedDateTime", "", "v2-partial"))
+ writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds.", "v2-partial"))
}
*******************************************************************************
@@ -3629,13 +3629,13 @@
=== Extended
-Note that the "extended" types require the addition of the separate `GraphSONXModuleV2d0` module as follows:
+Note that the "extended" types require the addition of the separate `GraphSONXModuleV2` module as follows:
[source,java]
----
mapper = GraphSONMapper.build().
typeInfo(TypeInfo.PARTIAL_TYPES).
- addCustomModule(GraphSONXModuleV2d0.build().create(false)).
+ addCustomModule(GraphSONXModuleV2.build()).
version(GraphSONVersion.V2_0).create().createMapper()
----
@@ -3853,16 +3853,16 @@
== Version 3.0
Version 3.0 of GraphSON was first introduced on TinkerPop 3.3.0 and is represented by the `application/vnd.graphbinary-v3.0`
-mime type. It is quite similar to GraphSON 2.0 and in most cases will appear compatible to the eye, however there are
-some critical differences:
+mime type. It was introduced as only having embedded types. It is quite similar to GraphSON 2.0 with embedded types
+and in most cases will appear compatible to the eye, however there are some critical differences. GraphSON 2.0 relied
+on JSON data types for collections like `Map` and `List`. In GraphSON 3.0, there is explicit typed support for `Map`,
+`List` and `Set` as Gremlin relies on those types in quite specific ways that are not directly compatible with the
+JSON definitions of those collections. In the case of `List` and `Set`, it was important to distinguish between the
+two and for `Map` it was necessary to have the ability to return `Map` instances that did not have `String` keys
+(e.g. `g.V().out().groupCount()`).
-* GraphSON 3.0 does not have an option to be typeless. Types are always embedded except for strings and boolean values
-which are inferred from JSON types.
-* GraphSON 2.0 relied on JSON data types for collections like `Map` and `List`. In GraphSON 3.0, there is explicit
-typed support for `Map`, `List` and `Set` as Gremlin relies on those types in quite specific ways that are not
-directly compatible with the JSON definitions of those collections. In the case of `List` and `Set`, it was important
-to distinguish between the two and for `Map` it was necessary to have the ability to return `Map` instances that did
-not have `String` keys (e.g. `g.V().out().groupCount()`).
+As of TinkerPop 3.7.0, GraphSON 3.0 also has a typeless representation referenced by the
+`application/vnd.graphbinary-v3.0;types=false`. This format matches the format developed for 1.0.
=== Core
@@ -5994,7 +5994,7 @@
----
mapper = GraphSONMapper.build().
typeInfo(TypeInfo.PARTIAL_TYPES).
- addCustomModule(GraphSONXModuleV3d0.build().create(false)).
+ addCustomModule(GraphSONXModuleV3.build()).
version(GraphSONVersion.V3_0).create().createMapper()
----
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index 93a509f..b05999c 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -1144,7 +1144,7 @@
===== GraphSON
-The GraphSON serializer produces human readable output in JSON format and is a good configuration choice for those
+The GraphSON serializer produces human-readable output in JSON format and is a good configuration choice for those
trying to use TinkerPop from non-JVM languages. JSON obviously has wide support across virtually all major
programming languages and can be consumed by a wide variety of tools. The format itself is described in the
link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[IO Documentation]. The following table shows the
@@ -1158,10 +1158,18 @@
|2.0 |yes |`application/vnd.gremlin-v2.0+json` |`GraphSONMessageSerializerV2d0`
|2.0 |no |`application/vnd.gremlin-v2.0+json;types=false` |`GraphSONUntypedMessageSerializerV2d0`
|3.0 |yes |`application/vnd.gremlin-v3.0+json` |`GraphSONMessageSerializerV3d0`
+|3.0 |no |`application/vnd.gremlin-v3.0+json;types=false` |`GraphSONMessageSerializerV3d0`
|=========================================================
The above serializer classes can be found in the `org.apache.tinkerpop.gremlin.util.ser` package of `gremlin-util`.
+NOTE: Gremlin can produce results that cannot be serialized with untyped GraphSON as the result simply cannot fit
+the structure JSON inherently allows. A simple example would be `g.V().groupCount()` which returns a `Map`. A `Map`
+is no problem for JSON, but the key to this `Map` is a `Vertex`, which is a complex object, and cannot be a key in
+JSON which only allows `String` keys. Untyped GraphSON will simply convert the `Vertex` to a `String` for purpose of
+serialization and as a result that data and type is lost. If this information is needed, switch to a typed format or
+adjust the Gremlin query in some way to return it in a different form that fits JSON structure.
+
Configuring GraphSON in the Gremlin Server configuration looks like this:
[source,yaml]
@@ -1212,11 +1220,6 @@
{"requestId":"9fdf0892-d86c-41f2-94b5-092785c473eb","status":{"message":"","code":200,"attributes":{"@type":"g:Map","@value":[]}},"result":{"data":{"@type":"g:List","@value":[{"@type":"g:Int32","@value":99}]},"meta":{"@type":"g:Map","@value":[]}}
----
-IMPORTANT: `GraphSONMessageSerializerGremlinV1d0` configures `application/vnd.gremlin-v1.0+json`, but this mime type does
-not support text serialization (i.e. `MessageTextSerializer`) which means that it cannot be used for the serializing
-results to the HTTP endpoint in Gremlin Server. GraphSON 1.0 must be configured with `application/json` using the
-`GraphSONMessageSerializerV1d0` as demonstrated above or use mimeType `application/vnd.gremlin-v1.0+json;types=false`.
-
[[server-graphbinary]]
===== GraphBinary
diff --git a/docs/src/upgrade/release-3.7.x.asciidoc b/docs/src/upgrade/release-3.7.x.asciidoc
index 4bb92a0..b556a2e 100644
--- a/docs/src/upgrade/release-3.7.x.asciidoc
+++ b/docs/src/upgrade/release-3.7.x.asciidoc
@@ -267,7 +267,8 @@
* `GraphSONMessageSerializerV2` is now typed GraphSON 2.0
* `GraphSONMessageSerializerGremlinV2d0` is removed - it was deprecated in 3.4.0 actually and served little purpose
* `GraphSONUntypedMessageSerializerV2` is now untyped GraphSON 2.0
-* `GraphSONMessageSerializerV3` is GraphSON 3.0
+* `GraphSONMessageSerializerV3` is typed GraphSON 3.0 as it always has been
+* `GraphSONUntypedMessageSerializerV3` is untyped GraphSON 3.0 which is newly added
==== Building and Running with JDK 17
diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
index c3bcbc6..0a302b5 100644
--- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
+++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/commands/BytecodeCommand.groovy
@@ -90,7 +90,7 @@
private def static createDefaultBuilder() {
def builder = GraphSONMapper.build().
- addCustomModule(GraphSONXModuleV3.build().create(false)).
+ addCustomModule(GraphSONXModuleV3.build()).
version(GraphSONVersion.V3_0)
def loadedTinkerGraph = false
diff --git a/gremlin-console/src/test/resources/org/apache/tinkerpop/gremlin/console/jsr223/gremlin-server-integration.yaml b/gremlin-console/src/test/resources/org/apache/tinkerpop/gremlin/console/jsr223/gremlin-server-integration.yaml
index cc60310..16080e7 100644
--- a/gremlin-console/src/test/resources/org/apache/tinkerpop/gremlin/console/jsr223/gremlin-server-integration.yaml
+++ b/gremlin-console/src/test/resources/org/apache/tinkerpop/gremlin/console/jsr223/gremlin-server-integration.yaml
@@ -25,10 +25,10 @@
org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]}}}}
serializers:
- - { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }} # application/vnd.gremlin-v3.0+gryo-stringd
- - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerGremlinV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1d0] }} # application/vnd.gremlin-v1.0+json
- - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }} # application/json,application/vnd.gremlin-v3.0+json
- - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
+ - { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }} # application/vnd.gremlin-v3.0+gryo-stringd
+ - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV1, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1] }} # application/vnd.gremlin-v1.0+json
+ - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3] }} # application/json,application/vnd.gremlin-v3.0+json
+ - { className: org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV2, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2] }} # application/vnd.gremlin-v2.0+json
processors:
- { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}
- { className: org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
index ff07ddf..9e65594 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
@@ -78,11 +78,7 @@
this.normalize = builder.normalize;
this.version = builder.version;
this.streamReadConstraints = builder.streamReadConstraintsBuilder.build();
-
- if (null == builder.typeInfo)
- this.typeInfo = builder.version == GraphSONVersion.V1_0 ? TypeInfo.NO_TYPES : TypeInfo.PARTIAL_TYPES;
- else
- this.typeInfo = builder.typeInfo;
+ this.typeInfo = builder.typeInfo;
}
@Override
@@ -90,7 +86,7 @@
final ObjectMapper om = new ObjectMapper(JsonFactory.builder().streamReadConstraints(streamReadConstraints).build());
om.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
- final GraphSONModule graphSONModule = version.getBuilder().create(normalize);
+ final GraphSONModule graphSONModule = version.getBuilder().create(normalize, typeInfo);
om.registerModule(graphSONModule);
customModules.forEach(om::registerModule);
@@ -98,11 +94,7 @@
if (loadCustomSerializers)
om.findAndRegisterModules();
- // graphson 3.0 only allows type - there is no option to remove embedded types
- if (version == GraphSONVersion.V3_0 && typeInfo == TypeInfo.NO_TYPES)
- throw new IllegalStateException(String.format("GraphSON 3.0 does not support %s", TypeInfo.NO_TYPES));
-
- if (version == GraphSONVersion.V3_0 || (version == GraphSONVersion.V2_0 && typeInfo != TypeInfo.NO_TYPES)) {
+ if ((version == GraphSONVersion.V3_0 || version == GraphSONVersion.V2_0) && typeInfo != TypeInfo.NO_TYPES) {
final GraphSONTypeIdResolver graphSONTypeIdResolver = new GraphSONTypeIdResolver();
final TypeResolverBuilder typer = new GraphSONTypeResolverBuilder(version)
.typesEmbedding(this.typeInfo)
@@ -142,8 +134,10 @@
.typeProperty(GraphSONTokens.CLASS);
om.setDefaultTyping(typer);
}
+ } else if (version == GraphSONVersion.V3_0) {
+
} else {
- throw new IllegalStateException("Unknown GraphSONVersion : " + version);
+ throw new IllegalStateException("Unknown GraphSONVersion: " + version);
}
// this provider toStrings all unknown classes and converts keys in Map objects that are Object to String.
@@ -201,6 +195,7 @@
public static class Builder implements Mapper.Builder<Builder> {
private List<SimpleModule> customModules = new ArrayList<>();
+ private List<GraphSONModule.GraphSONModuleBuilder> customModuleBuilders = new ArrayList<>();
private boolean loadCustomModules = false;
private boolean normalize = false;
private List<IoRegistry> registries = new ArrayList<>();
@@ -208,11 +203,6 @@
private boolean includeDefaultXModule = false;
private StreamReadConstraints.Builder streamReadConstraintsBuilder = StreamReadConstraints.builder()
.maxNumberLength(DEFAULT_MAX_NUMBER_LENGTH);
-
- /**
- * GraphSON 2.0/3.0 should have types activated by default (3.0 does not have a typeless option), and 1.0
- * should use no types by default.
- */
private TypeInfo typeInfo = null;
private Builder() {
@@ -252,6 +242,17 @@
}
/**
+ * Supplies a mapper module builder to be lazily constructed. The advantage to using this mechanism over
+ * {@link #addCustomModule(SimpleModule)} is that if the module is constructed with {@link TypeInfo} it can
+ * inherit it from the value supplied to {@link #typeInfo(TypeInfo)} (as well as the {@link #normalize(boolean)}
+ * option.
+ */
+ public Builder addCustomModule(final GraphSONModule.GraphSONModuleBuilder moduleBuilder) {
+ this.customModuleBuilders.add(moduleBuilder);
+ return this;
+ }
+
+ /**
* Supply a default extension module of V2_0 and V3_0 for serialization/deserialization.
*/
public Builder addDefaultXModule(final boolean includeDefaultXModule) {
@@ -308,16 +309,33 @@
simpleModules.stream().map(Pair::getValue1).forEach(this.customModules::add);
});
+ typeInfo = inferTypeInfo(typeInfo, version);
+
+ // finish building off the modules.
+ customModuleBuilders.forEach(b -> {
+ this.addCustomModule(b.create(this.normalize, typeInfo));
+ });
+
if (includeDefaultXModule) {
if (this.version == GraphSONVersion.V2_0) {
- this.addCustomModule(GraphSONXModuleV2.build().create(false));
+ this.addCustomModule(GraphSONXModuleV2.build().create(this.normalize, typeInfo));
} else if (this.version == GraphSONVersion.V3_0) {
- this.addCustomModule(GraphSONXModuleV3.build().create(false));
+ this.addCustomModule(GraphSONXModuleV3.build().create(this.normalize, typeInfo));
}
}
return new GraphSONMapper(this);
}
+ /**
+ * User the version to infer the {@link TypeInfo} if it is not explicitly supplied. GraphSON 1.0 defaults to
+ * no types, since it's Jackson type system is fairly impenetrable, but we otherwise use types.
+ */
+ private static TypeInfo inferTypeInfo(final TypeInfo typeInfo, final GraphSONVersion version) {
+ if (null == typeInfo)
+ return version == GraphSONVersion.V1_0 ? TypeInfo.NO_TYPES : TypeInfo.PARTIAL_TYPES;
+ else
+ return typeInfo;
+ }
}
}
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 4cbba78..86fc011 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
@@ -225,14 +225,14 @@
/**
* Constructs a new object.
*/
- protected GraphSONModuleV3(final boolean normalize) {
+ protected GraphSONModuleV3(final boolean normalize, final TypeInfo typeInfo) {
super("graphson-3.0");
/////////////////////// SERIALIZERS ////////////////////////////
// graph
- addSerializer(Edge.class, new GraphSONSerializersV3.EdgeJacksonSerializer(normalize));
- addSerializer(Vertex.class, new GraphSONSerializersV3.VertexJacksonSerializer(normalize));
+ addSerializer(Edge.class, new GraphSONSerializersV3.EdgeJacksonSerializer(normalize, typeInfo));
+ addSerializer(Vertex.class, new GraphSONSerializersV3.VertexJacksonSerializer(normalize, typeInfo));
addSerializer(VertexProperty.class, new GraphSONSerializersV3.VertexPropertyJacksonSerializer(normalize, true));
addSerializer(Property.class, new GraphSONSerializersV3.PropertyJacksonSerializer());
addSerializer(Metrics.class, new GraphSONSerializersV3.MetricsJacksonSerializer());
@@ -242,13 +242,15 @@
addSerializer(DirectionalStarGraph.class, new StarGraphGraphSONSerializerV3(normalize));
addSerializer(Tree.class, new GraphSONSerializersV3.TreeJacksonSerializer());
- // java.util
- addSerializer(Map.Entry.class, new JavaUtilSerializersV3.MapEntryJacksonSerializer());
- addSerializer(Map.class, new JavaUtilSerializersV3.MapJacksonSerializer());
- addSerializer(List.class, new JavaUtilSerializersV3.ListJacksonSerializer());
- addSerializer(Set.class, new JavaUtilSerializersV3.SetJacksonSerializer());
+ // java.util - use the standard jackson serializers for collections when types aren't embedded
+ if (typeInfo != TypeInfo.NO_TYPES) {
+ addSerializer(Map.Entry.class, new JavaUtilSerializersV3.MapEntryJacksonSerializer());
+ addSerializer(Map.class, new JavaUtilSerializersV3.MapJacksonSerializer());
+ addSerializer(List.class, new JavaUtilSerializersV3.ListJacksonSerializer());
+ addSerializer(Set.class, new JavaUtilSerializersV3.SetJacksonSerializer());
+ }
- // need to explicitly add serializers for those types because Jackson doesn't do it at all.
+ // need to explicitly add serializers for these types because Jackson doesn't do it at all.
addSerializer(Integer.class, new GraphSONSerializersV3.IntegerGraphSONSerializer());
addSerializer(Double.class, new GraphSONSerializersV3.DoubleGraphSONSerializer());
@@ -373,8 +375,8 @@
}
@Override
- public GraphSONModule create(final boolean normalize) {
- return new GraphSONModuleV3(normalize);
+ public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) {
+ return new GraphSONModuleV3(normalize, typeInfo);
}
}
@@ -604,7 +606,7 @@
}
@Override
- public GraphSONModule create(final boolean normalize) {
+ public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) {
return new GraphSONModuleV2(normalize);
}
@@ -687,7 +689,7 @@
}
@Override
- public GraphSONModule create(final boolean normalize) {
+ public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) {
return new GraphSONModuleV1(normalize);
}
}
@@ -702,9 +704,10 @@
/**
* Creates a new {@link GraphSONModule} object.
*
- * @param normalize when set to true, keys and objects are ordered to ensure that they are the occur in
+ * @param normalize when set to true, keys and objects are ordered to ensure that they occur in
* the same order.
+ * @param typeInfo allows the module to react to the specified typeinfo given to the mapper
*/
- GraphSONModule create(final boolean normalize);
+ GraphSONModule create(final boolean normalize, final TypeInfo typeInfo);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
index 25f7166..2d9024a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
@@ -87,10 +87,12 @@
final static class VertexJacksonSerializer extends StdScalarSerializer<Vertex> {
private final boolean normalize;
+ private final TypeInfo typeInfo;
- public VertexJacksonSerializer(final boolean normalize) {
+ public VertexJacksonSerializer(final boolean normalize, final TypeInfo typeInfo) {
super(Vertex.class);
this.normalize = normalize;
+ this.typeInfo = typeInfo;
}
@Override
@@ -100,13 +102,14 @@
jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.id());
jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label());
- writeProperties(vertex, jsonGenerator);
+ writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, GraphSONTokens.VERTEX);
+ writeProperties(vertex, jsonGenerator, serializerProvider);
jsonGenerator.writeEndObject();
}
- private void writeProperties(final Vertex vertex, final JsonGenerator jsonGenerator) throws IOException {
+ private void writeProperties(final Vertex vertex, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
if (vertex.keys().size() == 0)
return;
jsonGenerator.writeFieldName(GraphSONTokens.PROPERTIES);
@@ -122,7 +125,14 @@
jsonGenerator.writeStartArray();
while (vertexProperties.hasNext()) {
- jsonGenerator.writeObject(vertexProperties.next());
+ // if you writeObject the property directly it treats it as a standalone VertexProperty which
+ // will write the label duplicating it. we really only want that for embedded types
+ if (typeInfo == TypeInfo.NO_TYPES) {
+ VertexPropertyJacksonSerializer.writeVertexProperty(vertexProperties.next(), jsonGenerator,
+ serializerProvider, normalize, false);
+ } else {
+ jsonGenerator.writeObject(vertexProperties.next());
+ }
}
jsonGenerator.writeEndArray();
}
@@ -136,9 +146,12 @@
private final boolean normalize;
- public EdgeJacksonSerializer(final boolean normalize) {
+ private final TypeInfo typeInfo;
+
+ public EdgeJacksonSerializer(final boolean normalize, final TypeInfo typeInfo) {
super(Edge.class);
this.normalize = normalize;
+ this.typeInfo = typeInfo;
}
@@ -149,6 +162,7 @@
jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id());
jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label());
+ writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, GraphSONTokens.EDGE);
jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label());
jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label());
jsonGenerator.writeObjectField(GraphSONTokens.IN, edge.inVertex().id());
@@ -165,7 +179,10 @@
jsonGenerator.writeFieldName(GraphSONTokens.PROPERTIES);
jsonGenerator.writeStartObject();
- elementProperties.forEachRemaining(prop -> safeWriteObjectField(jsonGenerator, prop.key(), prop));
+ if (typeInfo == TypeInfo.NO_TYPES)
+ elementProperties.forEachRemaining(prop -> safeWriteObjectField(jsonGenerator, prop.key(), prop.value()));
+ else
+ elementProperties.forEachRemaining(prop -> safeWriteObjectField(jsonGenerator, prop.key(), prop));
jsonGenerator.writeEndObject();
}
}
@@ -201,6 +218,13 @@
@Override
public void serialize(final VertexProperty property, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
throws IOException {
+ writeVertexProperty(property, jsonGenerator, serializerProvider, normalize, includeLabel);
+ }
+
+ private static void writeVertexProperty(final VertexProperty property, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider, final boolean normalize,
+ final boolean includeLabel)
+ throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeObjectField(GraphSONTokens.ID, property.id());
@@ -759,4 +783,14 @@
return true;
}
}
+
+ /**
+ * When doing untyped serialization graph objects get a special "type" field appended.
+ */
+ private static void writeTypeForGraphObjectIfUntyped(final JsonGenerator jsonGenerator, final TypeInfo typeInfo,
+ final String type) throws IOException {
+ if (typeInfo == TypeInfo.NO_TYPES) {
+ jsonGenerator.writeStringField(GraphSONTokens.TYPE, type);
+ }
+ }
}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV2.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV2.java
index ccfa7ec..e147e4c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV2.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV2.java
@@ -133,7 +133,7 @@
}
@Override
- public GraphSONModule create(final boolean normalize) {
+ public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) {
return new GraphSONXModuleV2(normalize);
}
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV3.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV3.java
index 2508bc0..05b6841 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV3.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONXModuleV3.java
@@ -113,7 +113,7 @@
addDeserializer(ZoneOffset.class, new JavaTimeSerializersV3.ZoneOffsetJacksonDeserializer());
}
- public static Builder build() {
+ public static GraphSONModuleBuilder build() {
return new Builder();
}
@@ -133,7 +133,7 @@
}
@Override
- public GraphSONModule create(final boolean normalize) {
+ public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) {
return new GraphSONXModuleV3(normalize);
}
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
index ec991d0..9959484 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
@@ -75,10 +75,10 @@
return Arrays.asList(new Object[][]{
{"v1", GraphSONMapper.build().version(GraphSONVersion.V1_0).typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()},
{"v2", GraphSONMapper.build().version(GraphSONVersion.V2_0)
- .addCustomModule(GraphSONXModuleV2.build().create(false))
+ .addCustomModule(GraphSONXModuleV2.build())
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()},
{"v3", GraphSONMapper.build().version(GraphSONVersion.V3_0)
- .addCustomModule(GraphSONXModuleV3.build().create(false))
+ .addCustomModule(GraphSONXModuleV3.build())
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()}
});
}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
index a84fbb0..4b07c95 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
@@ -64,21 +64,20 @@
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][]{
{"v2", GraphSONMapper.build().version(GraphSONVersion.V2_0)
- .addCustomModule(GraphSONXModuleV2.build().create(false))
+ .addCustomModule(GraphSONXModuleV2.build())
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()},
{"v3", GraphSONMapper.build().version(GraphSONVersion.V3_0)
- .addCustomModule(GraphSONXModuleV3.build().create(false))
+ .addCustomModule(GraphSONXModuleV3.build())
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()}
});
}
- @Parameterized.Parameter(1)
- public ObjectMapper mapper;
-
-
@Parameterized.Parameter(0)
public String version;
+ @Parameterized.Parameter(1)
+ public ObjectMapper mapper;
+
@Test
public void elementOrderShouldNotMatter() throws Exception {
final String bytecodeJSONFail1 = "{\"@type\":\"g:Bytecode\",\"@value\":{\"step\":[[\"addV\",\"poc_int\"],[\"property\",\"bigint1value\",{\"@type\":\"g:Int32\",\"@value\":-4294967295}]]}}";
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java
index 7f7327b..21089da 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java
@@ -18,7 +18,17 @@
*/
package org.apache.tinkerpop.gremlin.structure.io.graphson;
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ImmutablePath;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+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.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +48,9 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__;
import static org.junit.Assert.assertEquals;
@@ -48,21 +61,99 @@
@RunWith(Parameterized.class)
public class GraphSONMapperTest {
- /**
- * No need to test V3 as it does not have an option to be constructed without types
- */
@Parameterized.Parameters(name = "{0}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][]{
- {GraphSONMapper.build().version(GraphSONVersion.V1_0).typeInfo(TypeInfo.NO_TYPES).create().createMapper()},
- {GraphSONMapper.build().version(GraphSONVersion.V2_0).addCustomModule(GraphSONXModuleV2.build().create(false)).typeInfo(TypeInfo.NO_TYPES).create().createMapper()},
- {GraphSONMapper.build().version(GraphSONVersion.V2_0).addDefaultXModule(true).typeInfo(TypeInfo.NO_TYPES).create().createMapper()}, // alternate construction of v2
+ {"v1", GraphSONMapper.build().version(GraphSONVersion.V1_0).typeInfo(TypeInfo.NO_TYPES).create().createMapper()},
+ {"v2", GraphSONMapper.build().version(GraphSONVersion.V2_0).addCustomModule(GraphSONXModuleV2.build()).typeInfo(TypeInfo.NO_TYPES).create().createMapper()},
+ {"v2-default", GraphSONMapper.build().version(GraphSONVersion.V2_0).addDefaultXModule(true).typeInfo(TypeInfo.NO_TYPES).create().createMapper()}, // alternate construction of v2
+ {"v3", GraphSONMapper.build().version(GraphSONVersion.V3_0).addCustomModule(GraphSONXModuleV3.build()).typeInfo(TypeInfo.NO_TYPES).create().createMapper()},
});
}
- @Parameterized.Parameter
+ @Parameterized.Parameter(0)
+ public String version;
+
+ @Parameterized.Parameter(1)
public ObjectMapper mapper;
+ @Test
+ public void shouldHandleVertex() throws Exception {
+ final Vertex v = new DetachedVertex(123L, "person", Arrays.asList(
+ DetachedVertexProperty.build().setId(1).setLabel("name").setValue("alice").create(),
+ DetachedVertexProperty.build().setId(1).setLabel("age").setValue("31").create()));
+ final String json = mapper.writeValueAsString(v);
+
+ // v2 untyped seems to serialize the VertexProperty label. not changing that since it's already been
+ // introduced a long while back. v3 dips back to v1 style - since it has never existed prior to 3.7.0
+ // we can make this change
+ if (version.startsWith("v1") || version.startsWith("v3"))
+ assertEquals("{\"id\":123,\"label\":\"person\",\"type\":\"vertex\",\"properties\":{\"name\":[{\"id\":1,\"value\":\"alice\"}],\"age\":[{\"id\":1,\"value\":\"31\"}]}}", json);
+ else if (version.startsWith("v2"))
+ assertEquals("{\"id\":123,\"label\":\"person\",\"properties\":{\"name\":[{\"id\":1,\"value\":\"alice\",\"label\":\"name\"}],\"age\":[{\"id\":1,\"value\":\"31\",\"label\":\"age\"}]}}", json);
+ else
+ throw new IllegalStateException("Version not accounted for in asserts");
+ }
+
+ @Test
+ public void shouldHandleEdge() throws Exception {
+ final Edge e = new DetachedEdge(123L, "knows", new HashMap<String,Object>() {{
+ put("weight", 0.5d);
+ }}, 1L, "person", 2L, "person");
+ final String json = mapper.writeValueAsString(e);
+
+ // v2 untyped seems to serialize the VertexProperty label. not changing that since it's already been
+ // introduced a long while back. v3 dips back to v1 style - since it has never existed prior to 3.7.0
+ // we can make this change
+ if (version.startsWith("v1") || version.startsWith("v3"))
+ assertEquals("{\"id\":123,\"label\":\"knows\",\"type\":\"edge\",\"inVLabel\":\"person\",\"outVLabel\":\"person\",\"inV\":2,\"outV\":1,\"properties\":{\"weight\":0.5}}", json);
+ else if (version.startsWith("v2"))
+ assertEquals("{\"id\":123,\"label\":\"knows\",\"inVLabel\":\"person\",\"outVLabel\":\"person\",\"inV\":2,\"outV\":1,\"properties\":{\"weight\":{\"key\":\"weight\",\"value\":0.5}}}", json);
+ else
+ throw new IllegalStateException("Version not accounted for in asserts");
+ }
+
+ @Test
+ public void shouldHandleProperty() throws Exception {
+ final Property p = new DetachedProperty("k", 123);
+ final String json = mapper.writeValueAsString(p);
+ assertEquals("{\"key\":\"k\",\"value\":123}", json);
+ }
+
+ @Test
+ public void shouldHandleVertexProperty() throws Exception {
+ final DetachedVertex v = new DetachedVertex(321L, "person", Collections.emptyMap());
+ final VertexProperty p = new DetachedVertexProperty(123L, "name", "alice",
+ new HashMap<String,Object>() {{
+ put("current", true);
+ }}, v);
+ final String json = mapper.writeValueAsString(p);
+ assertEquals("{\"id\":123,\"value\":\"alice\",\"label\":\"name\",\"properties\":{\"current\":true}}", json);
+ }
+
+ @Test
+ public void shouldHandleVertexPropertyNoMeta() throws Exception {
+ final DetachedVertex v = new DetachedVertex(321L, "person", Collections.emptyMap());
+ final VertexProperty p = new DetachedVertexProperty(123L, "name", "alice", Collections.emptyMap(), v);
+ final String json = mapper.writeValueAsString(p);
+ assertEquals("{\"id\":123,\"value\":\"alice\",\"label\":\"name\"}", json);
+ }
+
+ @Test
+ public void shouldHandlePath() throws Exception {
+ final Vertex v = new DetachedVertex(123L, "person", Arrays.asList(
+ DetachedVertexProperty.build().setId(1).setLabel("name").setValue("alice").create(),
+ DetachedVertexProperty.build().setId(1).setLabel("age").setValue("31").create()));
+ final Path p = ImmutablePath.make().extend(v, new HashSet<>(Collections.singletonList("a"))).
+ extend(123L, new HashSet<>(Collections.singletonList("b"))).
+ extend("alice", new HashSet<>(Collections.singletonList("c")));
+ final String json = mapper.writeValueAsString(p);
+
+ if (version.startsWith("v1") || version.startsWith("v3"))
+ assertEquals("{\"labels\":[[\"a\"],[\"b\"],[\"c\"]],\"objects\":[{\"id\":123,\"label\":\"person\",\"type\":\"vertex\",\"properties\":{\"name\":[{\"id\":1,\"value\":\"alice\"}],\"age\":[{\"id\":1,\"value\":\"31\"}]}},123,\"alice\"]}", json);
+ else
+ assertEquals("{\"labels\":[[\"a\"],[\"b\"],[\"c\"]],\"objects\":[{\"id\":123,\"label\":\"person\",\"properties\":{\"name\":[{\"id\":1,\"value\":\"alice\",\"label\":\"name\"}],\"age\":[{\"id\":1,\"value\":\"31\",\"label\":\"age\"}]}},123,\"alice\"]}", json);
+ }
@Test
public void shouldHandleTraversalExplanation() throws Exception {
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
index 9501c43..dcacd60 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
@@ -28,6 +28,7 @@
import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3;
import org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV1;
import org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV2;
+import org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV3;
import org.apache.tinkerpop.gremlin.util.ser.SerTokens;
import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
@@ -126,6 +127,9 @@
final Settings.SerializerSettings serializerSettingsTypedV2 = new Settings.SerializerSettings();
serializerSettingsTypedV2.className = GraphSONMessageSerializerV2.class.getName();
settings.serializers.add(serializerSettingsTypedV2);
+ final Settings.SerializerSettings serializerSettingsUntypedV3 = new Settings.SerializerSettings();
+ serializerSettingsUntypedV3.className = GraphSONUntypedMessageSerializerV3.class.getName();
+ settings.serializers.add(serializerSettingsUntypedV3);
final Settings.SerializerSettings serializerSettingsTypedV3 = new Settings.SerializerSettings();
serializerSettingsTypedV3.className = GraphSONMessageSerializerV3.class.getName();
settings.serializers.add(serializerSettingsTypedV3);
@@ -988,6 +992,19 @@
final JsonNode node = mapper.readTree(json);
assertEquals(0, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).asInt());
}
+
+ final HttpPost httppost3Untyped = new HttpPost(TestClientFactory.createURLString());
+ httppost3Untyped.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON);
+ httppost3Untyped.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V3_UNTYPED);
+ httppost3Untyped.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8));
+
+ try (final CloseableHttpResponse response = httpclient.execute(httppost3Untyped)) {
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ assertEquals(SerTokens.MIME_GRAPHSON_V3_UNTYPED, response.getEntity().getContentType().getValue());
+ final String json = EntityUtils.toString(response.getEntity());
+ final JsonNode node = mapper.readTree(json);
+ assertEquals(0, node.get("result").get("data").get(0).asInt());
+ }
}
@Test
diff --git a/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphSONMapperBenchmark.java b/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphSONMapperBenchmark.java
index 6c1c888..4974e9f 100644
--- a/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphSONMapperBenchmark.java
+++ b/gremlin-tools/gremlin-benchmark/src/main/java/org/apache/tinkerpop/gremlin/driver/GraphSONMapperBenchmark.java
@@ -23,7 +23,6 @@
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.openjdk.jmh.annotations.Benchmark;
@@ -46,7 +45,7 @@
public class GraphSONMapperBenchmark extends AbstractBenchmarkBase {
private static final ObjectMapper mapper = GraphSONMapper.build()
.version(GraphSONVersion.V3_0)
- .addCustomModule(GraphSONXModuleV3.build().create(false))
+ .addDefaultXModule(true)
.create().createMapper();
@State(Scope.Thread)
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
index 9a53a8e..9bc02dc 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypedCompatibilityTest.java
@@ -39,13 +39,13 @@
private static ObjectMapper mapperV2 = GraphSONMapper.build().
addRegistry(TinkerIoRegistryV2.instance()).
typeInfo(TypeInfo.PARTIAL_TYPES).
- addCustomModule(GraphSONXModuleV2.build().create(false)).
+ addCustomModule(GraphSONXModuleV2.build()).
addCustomModule(new AbstractGraphSONMessageSerializerV2.GremlinServerModule()).
version(GraphSONVersion.V2_0).create().createMapper();
private static ObjectMapper mapperV3 = GraphSONMapper.build().
addRegistry(TinkerIoRegistryV3.instance()).
- addCustomModule(GraphSONXModuleV3.build().create(false)).
+ addCustomModule(GraphSONXModuleV3.build()).
addCustomModule(new GraphSONMessageSerializerV3.GremlinServerModule()).
version(GraphSONVersion.V3_0).create().createMapper();
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
index 3d88587..5283f66 100644
--- a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONUntypedCompatibilityTest.java
@@ -45,7 +45,7 @@
private static ObjectMapper mapperV2 = GraphSONMapper.build().
addRegistry(TinkerIoRegistryV2.instance()).
typeInfo(TypeInfo.NO_TYPES).
- addCustomModule(GraphSONXModuleV2.build().create(false)).
+ addCustomModule(GraphSONXModuleV2.build()).
addCustomModule(new AbstractGraphSONMessageSerializerV2.GremlinServerModule()).
version(GraphSONVersion.V2_0).create().createMapper();
diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV2.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV2.java
index 521a426..87f8230 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV2.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV2.java
@@ -140,7 +140,7 @@
private GraphSONMapper.Builder initBuilder(final GraphSONMapper.Builder builder) {
final GraphSONMapper.Builder b = null == builder ? GraphSONMapper.build() : builder;
- return b.addCustomModule(GraphSONXModuleV2.build().create(false))
+ return b.addCustomModule(GraphSONXModuleV2.build())
.version(GraphSONVersion.V2_0);
}
diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2.java
index 40959e5..eae64c4 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2.java
@@ -61,15 +61,6 @@
}
/**
- * Create a GraphSONMessageSerializer from a {@link GraphSONMapper}. Deprecated, use
- * {@link #GraphSONUntypedMessageSerializerV2(GraphSONMapper.Builder)} instead.
- */
- @Deprecated
- public GraphSONUntypedMessageSerializerV2(final GraphSONMapper mapper) {
- super(mapper);
- }
-
- /**
* Create a GraphSONMessageSerializer with a provided {@link GraphSONMapper.Builder}.
*
* Note that to make this mapper usable in the context of request messages and responses,
diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3.java
new file mode 100644
index 0000000..9dffa21
--- /dev/null
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.util.ser;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
+import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.util.message.ResponseMessage;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Serialize results to JSON with version 3.0.x schema and the extended module without embedded types.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class GraphSONUntypedMessageSerializerV3 extends AbstractGraphSONMessageSerializerV2 implements MessageTextSerializer<ObjectMapper> {
+ private static final Logger logger = LoggerFactory.getLogger(GraphSONUntypedMessageSerializerV3.class);
+ private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V3_UNTYPED;
+
+ private static byte[] header;
+
+ static {
+ final ByteBuffer buffer = ByteBuffer.allocate(MIME_TYPE.length() + 1);
+ buffer.put((byte) MIME_TYPE.length());
+ buffer.put(MIME_TYPE.getBytes());
+ header = buffer.array();
+ }
+
+ /**
+ * Creates a default GraphSONMessageSerializer.
+ *
+ * By default this will internally instantiate a {@link GraphSONMapper} and register
+ * a {@link GremlinServerModule} and {@link GraphSONXModuleV2} to the mapper.
+ *
+ * @see #GraphSONUntypedMessageSerializerV3(GraphSONMapper.Builder)
+ */
+ public GraphSONUntypedMessageSerializerV3() {
+ super();
+ }
+
+ /**
+ * Create a GraphSONMessageSerializer with a provided {@link GraphSONMapper.Builder}.
+ *
+ * Note that to make this mapper usable in the context of request messages and responses,
+ * this method will automatically register a {@link GremlinServerModule} to the provided
+ * mapper.
+ */
+ public GraphSONUntypedMessageSerializerV3(final GraphSONMapper.Builder mapperBuilder) {
+ super(mapperBuilder);
+ }
+
+ @Override
+ public String[] mimeTypesSupported() {
+ return new String[]{MIME_TYPE, SerTokens.MIME_JSON};
+ }
+
+ @Override
+ GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) {
+ return builder.typeInfo(TypeInfo.NO_TYPES).addCustomModule(new GremlinServerModule());
+ }
+
+ @Override
+ byte[] obtainHeader() {
+ return header;
+ }
+
+ @Override
+ public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+ try {
+ return mapper.readValue(msg, ResponseMessage.class);
+ } catch (Exception ex) {
+ logger.warn("Response [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+ try {
+ return mapper.writeValueAsString(responseMessage);
+ } catch (Exception ex) {
+ logger.warn("Response [{}] could not be serialized by {}.", responseMessage.toString(), AbstractGraphSONMessageSerializerV2.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+ try {
+ return mapper.readValue(msg, RequestMessage.class);
+ } catch (Exception ex) {
+ logger.warn("Request [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+ try {
+ return mapper.writeValueAsString(requestMessage);
+ } catch (Exception ex) {
+ logger.warn("Request [{}] could not be serialized by {}.", requestMessage.toString(), AbstractGraphSONMessageSerializerV2.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+}
diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java
index 978e5d6..8be6d74 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/SerTokens.java
@@ -42,5 +42,6 @@
public static final String MIME_GRAPHSON_V2 = "application/vnd.gremlin-v2.0+json";
public static final String MIME_GRAPHSON_V2_UNTYPED = "application/vnd.gremlin-v2.0+json;types=false";
public static final String MIME_GRAPHSON_V3 = "application/vnd.gremlin-v3.0+json";
+ public static final String MIME_GRAPHSON_V3_UNTYPED = "application/vnd.gremlin-v3.0+json;types=false";
public static final String MIME_GRAPHBINARY_V1 = "application/vnd.graphbinary-v1.0";
}
diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/Serializers.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/Serializers.java
index d3134c7..3aad5e3 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/Serializers.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/Serializers.java
@@ -38,7 +38,7 @@
GRAPHSON_V1(SerTokens.MIME_GRAPHSON_V1),
/**
- * GraphSON 2.0 without types.
+ * GraphSON 1.0 without types.
*/
GRAPHSON_V1_UNTYPED(SerTokens.MIME_GRAPHSON_V1_UNTYPED),
@@ -58,6 +58,11 @@
GRAPHSON_V3(SerTokens.MIME_GRAPHSON_V3),
/**
+ * GraphSON 3.0 without types.
+ */
+ GRAPHSON_V3_UNTYPED(SerTokens.MIME_GRAPHSON_V3_UNTYPED),
+
+ /**
* GraphBinary 1.0.
*/
GRAPHBINARY_V1(SerTokens.MIME_GRAPHBINARY_V1);
@@ -85,6 +90,8 @@
return new GraphSONMessageSerializerV2();
case SerTokens.MIME_GRAPHSON_V2_UNTYPED:
return new GraphSONUntypedMessageSerializerV2();
+ case SerTokens.MIME_GRAPHSON_V3_UNTYPED:
+ return new GraphSONUntypedMessageSerializerV3();
case SerTokens.MIME_GRAPHBINARY_V1:
return new GraphBinaryMessageSerializerV1();
default:
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV2Test.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV2Test.java
index d013d6f..54ce7cd 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV2Test.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV2Test.java
@@ -547,7 +547,7 @@
@Test
public void shouldRegisterGremlinServerModuleAutomaticallyWithMapper() throws SerializationException {
- GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2.build().create(false));
+ GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2.build());
GraphSONMessageSerializerV2 graphSONMessageSerializerV2 = new GraphSONMessageSerializerV2(builder);
ResponseMessage rm = convert("hello", graphSONMessageSerializerV2);
@@ -559,7 +559,7 @@
@Test
@SuppressWarnings("deprecation")
public void shouldFailOnMessageSerializerWithMapperIfNoGremlinServerModule() {
- final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2.build().create(false));
+ final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV2.build());
final GraphSONMessageSerializerV2 graphSONMessageSerializerV2 = new GraphSONMessageSerializerV2(builder.create());
try {
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV3Test.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV3Test.java
index cfa6d77..97cce80 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV3Test.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONMessageSerializerV3Test.java
@@ -348,7 +348,7 @@
@Test
public void shouldRegisterGremlinServerModuleAutomaticallyWithMapper() throws SerializationException {
- GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3.build().create(false));
+ GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3.build());
GraphSONMessageSerializerV3 graphSONMessageSerializerV3 = new GraphSONMessageSerializerV3(builder);
ResponseMessage rm = convert("hello", graphSONMessageSerializerV3);
@@ -358,7 +358,7 @@
@Test
public void shouldFailOnMessageSerializerWithMapperIfNoGremlinServerModule() {
- final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3.build().create(false));
+ final GraphSONMapper.Builder builder = GraphSONMapper.build().addCustomModule(GraphSONXModuleV3.build());
final GraphSONMessageSerializerV3 graphSONMessageSerializerV3 = new GraphSONMessageSerializerV3(builder.create());
try {
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2Test.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2Test.java
index 2c06482..4eae80b 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2Test.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2Test.java
@@ -85,9 +85,9 @@
@Test
public void shouldConfigureIoRegistry() throws Exception {
- final GraphSONUntypedMessageSerializerV1 serializer = new GraphSONUntypedMessageSerializerV1();
+ final GraphSONUntypedMessageSerializerV2 serializer = new GraphSONUntypedMessageSerializerV2();
final Map<String, Object> config = new HashMap<String, Object>() {{
- put(AbstractMessageSerializer.TOKEN_IO_REGISTRIES, Arrays.asList(GraphSONUntypedMessageSerializerV1Test.ColorIoRegistry.class.getName()));
+ put(AbstractMessageSerializer.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
}};
serializer.configure(config, null);
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3Test.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3Test.java
new file mode 100644
index 0000000..6534062
--- /dev/null
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3Test.java
@@ -0,0 +1,471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.util.ser;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.util.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
+import org.apache.tinkerpop.shaded.jackson.databind.node.NullNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+/**
+ * These tests focus on message serialization and not "result" serialization as test specific to results (e.g.
+ * vertices, edges, annotated values, etc.) are handled in the IO packages.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GraphSONUntypedMessageSerializerV3Test {
+ public static final GraphSONUntypedMessageSerializerV3 SERIALIZER = new GraphSONUntypedMessageSerializerV3();
+ private static final RequestMessage msg = RequestMessage.build("op")
+ .overrideRequestId(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595")).create();
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private static final ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
+
+ @Test
+ public void shouldConfigureIoRegistry() throws Exception {
+ final GraphSONUntypedMessageSerializerV3 serializer = new GraphSONUntypedMessageSerializerV3();
+ final Map<String, Object> config = new HashMap<String, Object>() {{
+ put(AbstractMessageSerializer.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
+ }};
+
+ serializer.configure(config, null);
+
+ final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
+ .result(Color.RED).create();
+ final String results = serializer.serializeResponseAsString(toSerialize, allocator);
+ final JsonNode json = mapper.readTree(results);
+ assertNotNull(json);
+ assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
+ }
+
+ @Test
+ public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
+ final ResponseMessage message = ResponseMessage.build(msg).create();
+ final String results = SERIALIZER.serializeResponseAsString(message, allocator);
+ final JsonNode json = mapper.readTree(results);
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.path(SerTokens.TOKEN_REQUEST).asText());
+ assertEquals(NullNode.getInstance(), json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA));
+ }
+
+ @Test
+ public void shouldSerializeToJsonIterable() throws Exception {
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(2, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals("y", converted.get(1).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIterator() throws Exception {
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(2, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals("y", converted.get(1).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIteratorNullElement() throws Exception {
+
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(null);
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(3, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals(NullNode.getInstance(), converted.get(1));
+ assertEquals("y", converted.get(2).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonMap() throws Exception {
+ final Map<String, Object> map = new HashMap<>();
+ final Map<String, String> innerMap = new HashMap<>();
+ innerMap.put("a", "b");
+
+ map.put("x", new FunObject("x"));
+ map.put("y", "some");
+ map.put("z", innerMap);
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(jsonObject);
+ assertEquals("some", jsonObject.get("y").asText());
+ assertEquals("x", jsonObject.get("x").asText());
+
+ final JsonNode innerJsonObject = jsonObject.get("z");
+ assertNotNull(innerJsonObject);
+ assertEquals("b", innerJsonObject.get("a").asText());
+ }
+
+ @Test
+ public void shouldShouldSerializeMapEntries() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v1 = graph.addVertex();
+ final Date d = new Date();
+
+ final Map<Object, Object> map = new HashMap<>();
+ map.put("x", 1);
+ map.put(v1, 100);
+ map.put(d, "test");
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+ jsonObject.elements().forEachRemaining(e -> {
+ if (e.has("x"))
+ assertEquals(1, e.get("x").asInt());
+ else if (e.has(v1.id().toString()))
+ assertEquals(100, e.get(v1.id().toString()).asInt());
+ else if (e.has(StdDateFormat.instance.format(d)))
+ assertEquals("test", e.get(StdDateFormat.instance.format(d)).asText());
+ else
+ fail("Map entries contains a key that is not part of what was serialized");
+ });
+ }
+
+ @Test
+ public void shouldSerializeEdge() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v1 = g.addVertex();
+ final Vertex v2 = g.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Edge> iterable = IteratorUtils.list(g.edges());
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode edgeAsJson = converted.get(0);
+ assertNotNull(edgeAsJson);
+
+ assertEquals(((Long) e.id()).intValue(), edgeAsJson.get(GraphSONTokens.ID).asLong()); // lossy
+ assertEquals(((Long) v1.id()).intValue(), edgeAsJson.get(GraphSONTokens.OUT).asLong());// lossy
+ assertEquals(((Long) v2.id()).intValue(), edgeAsJson.get(GraphSONTokens.IN).asLong()); // lossy
+ assertEquals(e.label(), edgeAsJson.get(GraphSONTokens.LABEL).asText());
+ assertEquals(e.inVertex().label(), edgeAsJson.get(GraphSONTokens.IN_LABEL).asText());
+ assertEquals(e.outVertex().label(), edgeAsJson.get(GraphSONTokens.OUT_LABEL).asText());
+
+ final JsonNode properties = edgeAsJson.get(GraphSONTokens.PROPERTIES);
+ assertNotNull(properties);
+ assertEquals("abc", properties.get("abc").get(GraphSONTokens.KEY).textValue());
+ assertEquals(123, properties.get("abc").get(GraphSONTokens.VALUE).intValue());
+ }
+
+ @Test
+ public void shouldSerializeEdgeProperty() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v1 = g.addVertex();
+ final Vertex v2 = g.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode propertyAsJson = converted.get(0);
+ assertNotNull(propertyAsJson);
+
+ assertEquals(123, propertyAsJson.get("value").asInt());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIteratorWithEmbeddedMap() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v = g.addVertex();
+ final Map<String, Object> map = new HashMap<>();
+ map.put("x", 500);
+ map.put("y", "some");
+
+ final ArrayList<Object> friends = new ArrayList<>();
+ friends.add("x");
+ friends.add(5);
+ friends.add(map);
+
+ v.property(VertexProperty.Cardinality.single, "friends", friends);
+
+ final Iterable iterable = IteratorUtils.list(g.vertices());
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode vertexAsJson = converted.get(0);
+ assertNotNull(vertexAsJson);
+
+ final JsonNode properties = vertexAsJson.get(GraphSONTokens.PROPERTIES);
+ assertNotNull(properties);
+ assertEquals(1, properties.size());
+
+ final JsonNode friendProperties = properties.get("friends");
+ assertEquals(1, friendProperties.size());
+ final JsonNode friendsProperty = friendProperties.get(0);
+ assertNotNull(friendsProperty);
+ assertEquals(3, friends.size());
+
+ final String object1 = friendsProperty.get(GraphSONTokens.VALUE).get(0).asText();
+ assertEquals("x", object1);
+
+ final int object2 = friendsProperty.get(GraphSONTokens.VALUE).get(1).asInt();
+ assertEquals(5, object2);
+
+ final JsonNode object3 = friendsProperty.get(GraphSONTokens.VALUE).get(2);
+ assertEquals(500, object3.get("x").asInt());
+ assertEquals("some", object3.get("y").asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonMapWithElementForKey() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createClassic();
+ final GraphTraversalSource g = graph.traversal();
+ final Map<Vertex, Integer> map = new HashMap<>();
+ map.put(g.V().has("name", "marko").next(), 1000);
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+
+ // with no embedded types the key (which is a vertex) simply serializes out to an id
+ // {"result":{"1":1000},"code":200,"requestId":"2d62161b-9544-4f39-af44-62ec49f9a595","type":0}
+ assertEquals(1000, converted.get("1").asInt());
+ }
+
+ @Test
+ public void shouldDeserializeRequestNicelyWithNoArgs() throws Exception {
+ final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+ final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\"}", request));
+ assertEquals(request, m.getRequestId());
+ assertEquals("eval", m.getOp());
+ assertNotNull(m.getArgs());
+ assertEquals(0, m.getArgs().size());
+ }
+
+ @Test
+ public void shouldDeserializeRequestNicelyWithArgs() throws Exception {
+ final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+ final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}", request));
+ assertEquals(request, m.getRequestId());
+ assertEquals("eval", m.getOp());
+ assertNotNull(m.getArgs());
+ assertEquals("y", m.getArgs().get("x"));
+ }
+
+ @Test(expected = SerializationException.class)
+ public void shouldDeserializeRequestParseMessage() throws Exception {
+ SERIALIZER.deserializeRequest("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}");
+ }
+
+ @Test
+ public void shouldSerializeFullResponseMessage() throws Exception {
+ final UUID id = UUID.randomUUID();
+
+ final Map<String, Object> metaData = new HashMap<>();
+ metaData.put("test", "this");
+ metaData.put("one", 1);
+
+ final Map<String, Object> attributes = new HashMap<>();
+ attributes.put("test", "that");
+ attributes.put("two", 2);
+
+ final ResponseMessage response = ResponseMessage.build(id)
+ .responseMetaData(metaData)
+ .code(ResponseStatusCode.SUCCESS)
+ .result("some-result")
+ .statusAttributes(attributes)
+ .statusMessage("worked")
+ .create();
+
+ final String results = SERIALIZER.serializeResponseAsString(response, allocator);
+ final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
+
+ assertEquals(id, deserialized.getRequestId());
+ assertEquals("this", deserialized.getResult().getMeta().get("test"));
+ assertEquals(1, deserialized.getResult().getMeta().get("one"));
+ assertEquals("some-result", deserialized.getResult().getData());
+ assertEquals("that", deserialized.getStatus().getAttributes().get("test"));
+ assertEquals(2, deserialized.getStatus().getAttributes().get("two"));
+ assertEquals(ResponseStatusCode.SUCCESS.getValue(), deserialized.getStatus().getCode().getValue());
+ assertEquals("worked", deserialized.getStatus().getMessage());
+ }
+
+ @Test
+ public void shouldDeserializeResponseMessageWithNullMessage() throws Exception {
+ final UUID id = UUID.randomUUID();
+
+ final Map<String, Object> metaData = new HashMap<>();
+ metaData.put("test", UUID.randomUUID().toString());
+ final Map<String, Object> attributes = Collections.emptyMap();
+
+ final ResponseMessage response = ResponseMessage.build(id)
+ .responseMetaData(metaData)
+ .code(ResponseStatusCode.SERVER_ERROR)
+ .result("some-result")
+ .statusAttributes(attributes)
+ // explicitly pass the null value
+ .statusMessage(null)
+ .create();
+
+ final String results = SERIALIZER.serializeResponseAsString(response, allocator);
+ final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
+ Assert.assertNotNull(SERIALIZER.getClass().getSimpleName() + " should be able to deserialize ResponseMessage "
+ + "with null message field", deserialized);
+ }
+
+ private class FunObject {
+ private String val;
+
+ public FunObject(String val) {
+ this.val = val;
+ }
+
+ public String toString() {
+ return this.val;
+ }
+ }
+
+ public static class ColorIoRegistry extends AbstractIoRegistry {
+ public ColorIoRegistry() {
+ register(GraphSONIo.class, null, new GraphSONUntypedMessageSerializerV1Test.ColorSimpleModule());
+ }
+ }
+
+ public static class ColorSimpleModule extends SimpleModule {
+ public ColorSimpleModule() {
+ super("color-fun");
+ addSerializer(Color.class, new GraphSONUntypedMessageSerializerV1Test.ColorSerializer());
+
+ }
+ }
+
+ public static class ColorSerializer extends StdSerializer<Color> {
+ public ColorSerializer() {
+ super(Color.class);
+ }
+
+ @Override
+ public void serialize(final Color color, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider) throws IOException, JsonGenerationException {
+ jsonGenerator.writeBoolean(color.equals(Color.RED));
+ }
+ }
+}
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphGraphSONSerializerV2Test.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphGraphSONSerializerV2Test.java
index e66b825..3622795 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphGraphSONSerializerV2Test.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphGraphSONSerializerV2Test.java
@@ -64,13 +64,13 @@
// As of TinkerPop 3.2.1 default for GraphSON 2.0 means types enabled.
private final Mapper defaultMapperV2 = GraphSONMapper.build()
.version(GraphSONVersion.V2_0)
- .addCustomModule(GraphSONXModuleV2.build().create(false))
+ .addCustomModule(GraphSONXModuleV2.build())
.addRegistry(TinkerIoRegistryV2.instance())
.create();
private final Mapper noTypesMapperV2 = GraphSONMapper.build()
.version(GraphSONVersion.V2_0)
- .addCustomModule(GraphSONXModuleV2.build().create(false))
+ .addCustomModule(GraphSONXModuleV2.build())
.typeInfo(TypeInfo.NO_TYPES)
.addRegistry(TinkerIoRegistryV2.instance())
.create();
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/GraphSONTranslator.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/GraphSONTranslator.java
index 42dfc0d..c86ba01 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/GraphSONTranslator.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/GraphSONTranslator.java
@@ -30,6 +30,7 @@
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV3;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -53,10 +54,10 @@
final GraphSONMapper mapper;
if (version == GraphSONVersion.V2_0) {
mapper = GraphSONMapper.build()
- .addCustomModule(GraphSONXModuleV2.build().create(false)).version(GraphSONVersion.V2_0).create();
+ .addCustomModule(GraphSONXModuleV2.build()).version(GraphSONVersion.V2_0).create();
} else if (version == GraphSONVersion.V3_0) {
mapper = GraphSONMapper.build()
- .addCustomModule(GraphSONXModuleV3.build().create(false)).version(GraphSONVersion.V3_0).create();
+ .addCustomModule(GraphSONXModuleV3.build()).version(GraphSONVersion.V3_0).create();
} else {
throw new IllegalArgumentException("GraphSONVersion." + version.name() + " is not supported for testing");
}