This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch TINKERPOP-2967 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit d85d0a739fdbd5b623345805ea912d09dc7f669d Author: Stephen Mallette <stepm...@amazon.com> AuthorDate: Thu Jul 13 14:44:42 2023 -0400 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. --- CHANGELOG.asciidoc | 1 + docs/src/dev/io/graphson.asciidoc | 331 +++++++++++---------- docs/src/reference/gremlin-applications.asciidoc | 15 +- docs/src/upgrade/release-3.7.x.asciidoc | 3 +- .../structure/io/graphson/GraphSONMapper.java | 56 ++-- .../structure/io/graphson/GraphSONModule.java | 33 +- .../io/graphson/GraphSONSerializersV3.java | 46 ++- .../structure/io/graphson/GraphSONXModuleV2.java | 2 +- .../structure/io/graphson/GraphSONXModuleV3.java | 4 +- .../graphson/GraphSONMapperEmbeddedTypeTest.java | 4 +- .../GraphSONMapperPartialEmbeddedTypeTest.java | 11 +- .../structure/io/graphson/GraphSONMapperTest.java | 105 ++++++- .../server/GremlinServerHttpIntegrateTest.java | 49 ++- .../gremlin/driver/GraphSONMapperBenchmark.java | 3 +- .../graphson/GraphSONTypedCompatibilityTest.java | 4 +- .../graphson/GraphSONUntypedCompatibilityTest.java | 2 +- .../ser/AbstractGraphSONMessageSerializerV2.java | 2 +- .../ser/GraphSONUntypedMessageSerializerV2.java | 9 - ...ava => GraphSONUntypedMessageSerializerV3.java} | 28 +- .../tinkerpop/gremlin/util/ser/SerTokens.java | 1 + .../tinkerpop/gremlin/util/ser/Serializers.java | 9 +- .../util/ser/GraphSONMessageSerializerV2Test.java | 4 +- .../util/ser/GraphSONMessageSerializerV3Test.java | 4 +- .../GraphSONUntypedMessageSerializerV2Test.java | 4 +- ...=> GraphSONUntypedMessageSerializerV3Test.java} | 24 +- .../TinkerGraphGraphSONSerializerV2Test.java | 4 +- .../structure/io/graphson/GraphSONTranslator.java | 5 +- 27 files changed, 456 insertions(+), 307 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 0a22824924..ec6921c424 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -53,6 +53,7 @@ This release also includes changes from <<release-3-6-XXX, 3.6.XXX>>. * 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 efde29ceb4..1aa2bc10af 100644 --- a/docs/src/dev/io/graphson.asciidoc +++ b/docs/src/dev/io/graphson.asciidoc @@ -22,14 +22,14 @@ limitations under the License. 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 @@ toJson = { o, type, comment = "", suffix = "v1d0" -> } -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 @@ file.withWriter { writer -> } 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 [...] - 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 [...] + 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")) } ******************************************************************************* @@ -453,7 +453,7 @@ mime type is made explicit on requests to avoid breaking changes or unexpected r Version 1.0 of GraphSON was released with TinkerPop 3.0.0. It is referred to by the following mime types: * `application/vnd.gremlin-v1.0+json` - types embedded -* `application/vnd.gremlin-v1.0+json;sparse=true` - no types embedded +* `application/vnd.gremlin-v1.0+json;types=false` - no types embedded When types are embedded, GraphSON uses the standard link:https://github.com/FasterXML/jackson-databind[Jackson] type embedding approach that writes the full Java class @@ -1154,13 +1154,14 @@ do the opposite as embedded types is the expected manner in which non-JVM langua GraphSON 2.0 is referred to by the following mime types: -* `application/vnd.gremlin-v2.0+json` - All other values are typed by way of a "complex object" that defines a -`@typeId` and `@value`. The `@typeId` is composed of two parts: a namespace and a type name, in the format -"namespace:typename". A namespace allows TinkerPop providers and users to categorize custom types that they may -implement and avoid collision with existing TinkerPop types. By default, TinkerPop types will have the namespace "g" -(or "gx" for "extended" types). -* `application/vnd.gremlin-v2.0+json;sparse=true` - A non-typed value which is assumed the type implied by JSON. -These non-types are limited to `String`, `Boolean`, `Map` and `Collection`. +* `application/vnd.gremlin-v2.0+json` - Values are typed by way of a "complex object" that defines a `@typeId` and +`@value`. The `@typeId` is composed of two parts: a namespace and a type name, in the format "namespace:typename". A +namespace allows TinkerPop providers and users to categorize custom types that they may implement and avoid collision +with existing TinkerPop types. By default, TinkerPop types will have the namespace "g" (or "gx" for "extended" types). +* `application/vnd.gremlin-v2.0+json;types=false` - Values do not have their types embedded in the JSON. This format +does not follow the 1.0 untyped format in that it does not include a "type" field for `Vertex` and `Edge` objects and +it serializes property values in those graph objects with a `label` field which is redundant as the "key" field for +that property will already represent that value. === Core @@ -3628,13 +3629,13 @@ The following `ResponseMessage` is a typical example of the typical successful r === 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() ---- @@ -3852,16 +3853,16 @@ The following example is a `ZoneOffset` of three hours, six minutes, and nine se == 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 @@ -5993,7 +5994,7 @@ Note that the "extended" types require the addition of the separate `GraphSONXMo ---- 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 2f1b3cde8d..b05999cb61 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -1144,7 +1144,7 @@ drivers. ===== 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 @@ available GraphSON serializers that can be configured: |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 @@ $ curl -H "Accept:application/vnd.gremlin-v3.0+json" -X POST -d "{\"gremlin\":\" {"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;sparse=true`. - [[server-graphbinary]] ===== GraphBinary diff --git a/docs/src/upgrade/release-3.7.x.asciidoc b/docs/src/upgrade/release-3.7.x.asciidoc index a3d0e493a4..d0860d4e61 100644 --- a/docs/src/upgrade/release-3.7.x.asciidoc +++ b/docs/src/upgrade/release-3.7.x.asciidoc @@ -196,7 +196,8 @@ of this naming and given the previously mentioned removal of the "d0" we now hav * `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-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 eaaa5c7918..24e5e7759a 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 @@ -73,11 +73,7 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { this.loadCustomSerializers = builder.loadCustomModules; this.normalize = builder.normalize; this.version = builder.version; - - 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 @@ -85,7 +81,7 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { final ObjectMapper om = new ObjectMapper(); 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); @@ -93,11 +89,7 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { 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) @@ -137,8 +129,10 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { .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. @@ -195,16 +189,12 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { 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<>(); private GraphSONVersion version = GraphSONVersion.V3_0; private boolean includeDefaultXModule = false; - - /** - * 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() { @@ -243,6 +233,17 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { return this; } + /** + * 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. */ @@ -285,16 +286,33 @@ public class GraphSONMapper implements Mapper<ObjectMapper> { 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 4cbba78f84..86fc011208 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 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { /** * 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 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { 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 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { } @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 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { } @Override - public GraphSONModule create(final boolean normalize) { + public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) { return new GraphSONModuleV2(normalize); } @@ -687,7 +689,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { } @Override - public GraphSONModule create(final boolean normalize) { + public GraphSONModule create(final boolean normalize, final TypeInfo typeInfo) { return new GraphSONModuleV1(normalize); } } @@ -702,9 +704,10 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { /** * 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 25f7166fbc..2d9024aa60 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { 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 @@ class GraphSONSerializersV3 { @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 @@ class GraphSONSerializersV3 { 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 ccfa7ecbc6..e147e4cb40 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 @@ public final class GraphSONXModuleV2 extends GraphSONModule { } @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 2508bc0872..05b68416ea 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 @@ public final class GraphSONXModuleV3 extends GraphSONModule { addDeserializer(ZoneOffset.class, new JavaTimeSerializersV3.ZoneOffsetJacksonDeserializer()); } - public static Builder build() { + public static GraphSONModuleBuilder build() { return new Builder(); } @@ -133,7 +133,7 @@ public final class GraphSONXModuleV3 extends GraphSONModule { } @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 ec991d0b60..9959484468 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 @@ public class GraphSONMapperEmbeddedTypeTest extends AbstractGraphSONTest { 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 a84fbb03f3..4b07c95c67 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 class GraphSONMapperPartialEmbeddedTypeTest extends AbstractGraphSONTest 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 7f7327b0fc..21089daba4 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.YearMonth; 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 @@ import static org.junit.Assert.assertEquals; @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 23da00cf99..dcacd602eb 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.GraphSONMessageSerializerV2; 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; @@ -114,18 +115,21 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra break; case "should200OnPOSTWithAnyGraphSONAcceptHeaderDefaultResultToJson": settings.serializers.clear(); - final Settings.SerializerSettings serializerSettingsSparseV1 = new Settings.SerializerSettings(); - serializerSettingsSparseV1.className = GraphSONUntypedMessageSerializerV1.class.getName(); - settings.serializers.add(serializerSettingsSparseV1); + final Settings.SerializerSettings serializerSettingsUntypedV1 = new Settings.SerializerSettings(); + serializerSettingsUntypedV1.className = GraphSONUntypedMessageSerializerV1.class.getName(); + settings.serializers.add(serializerSettingsUntypedV1); final Settings.SerializerSettings serializerSettingsTypedV1 = new Settings.SerializerSettings(); serializerSettingsTypedV1.className = GraphSONMessageSerializerV1.class.getName(); settings.serializers.add(serializerSettingsTypedV1); - final Settings.SerializerSettings serializerSettingsSparseV2 = new Settings.SerializerSettings(); - serializerSettingsSparseV2.className = GraphSONUntypedMessageSerializerV2.class.getName(); - settings.serializers.add(serializerSettingsSparseV2); + final Settings.SerializerSettings serializerSettingsUntypedV2 = new Settings.SerializerSettings(); + serializerSettingsUntypedV2.className = GraphSONUntypedMessageSerializerV2.class.getName(); + settings.serializers.add(serializerSettingsUntypedV2); 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); @@ -937,12 +941,12 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra assertEquals(0, node.get("result").get("data").get(0).asInt()); } - final HttpPost httppost1Sparse = new HttpPost(TestClientFactory.createURLString()); - httppost1Sparse.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON); - httppost1Sparse.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V1_UNTYPED); - httppost1Sparse.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8)); + final HttpPost httppost1Untyped = new HttpPost(TestClientFactory.createURLString()); + httppost1Untyped.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON); + httppost1Untyped.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V1_UNTYPED); + httppost1Untyped.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8)); - try (final CloseableHttpResponse response = httpclient.execute(httppost1Sparse)) { + try (final CloseableHttpResponse response = httpclient.execute(httppost1Untyped)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(SerTokens.MIME_GRAPHSON_V1_UNTYPED, response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); @@ -963,12 +967,12 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra assertEquals(0, node.get("result").get("data").get(0).get(GraphSONTokens.VALUEPROP).asInt()); } - final HttpPost httppost2Sparse = new HttpPost(TestClientFactory.createURLString()); - httppost2Sparse.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON); - httppost2Sparse.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V2_UNTYPED); - httppost2Sparse.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8)); + final HttpPost httppost2Untyped = new HttpPost(TestClientFactory.createURLString()); + httppost2Untyped.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON); + httppost2Untyped.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V2_UNTYPED); + httppost2Untyped.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8)); - try (final CloseableHttpResponse response = httpclient.execute(httppost2Sparse)) { + try (final CloseableHttpResponse response = httpclient.execute(httppost2Untyped)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(SerTokens.MIME_GRAPHSON_V2_UNTYPED, response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); @@ -988,6 +992,19 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra 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 6c1c888e38..4974e9fc4c 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.process.traversal.Bytecode; 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 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; 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 9a53a8e72d..9bc02dc81f 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 @@ public class GraphSONTypedCompatibilityTest extends AbstractTypedCompatibilityTe 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 3d88587ef8..5283f66435 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 @@ public class GraphSONUntypedCompatibilityTest extends AbstractUntypedCompatibili 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 5049c902c2..57f0ecc5ef 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 @@ -139,7 +139,7 @@ public abstract class AbstractGraphSONMessageSerializerV2 extends AbstractMessag 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 40959e55cb..eae64c4fd4 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 @@ -60,15 +60,6 @@ public final class GraphSONUntypedMessageSerializerV2 extends AbstractGraphSONMe super(); } - /** - * 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}. * 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/GraphSONUntypedMessageSerializerV3.java similarity index 86% copy from gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2.java copy to gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3.java index 40959e55cb..9dffa216c3 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/GraphSONUntypedMessageSerializerV3.java @@ -19,11 +19,11 @@ package org.apache.tinkerpop.gremlin.util.ser; import io.netty.buffer.ByteBufAllocator; -import org.apache.tinkerpop.gremlin.util.message.RequestMessage; -import org.apache.tinkerpop.gremlin.util.message.ResponseMessage; 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; @@ -31,13 +31,13 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; /** - * Serialize results to JSON with version 2.0.x schema and the extended module without embedded types. + * 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 GraphSONUntypedMessageSerializerV2 extends AbstractGraphSONMessageSerializerV2 implements MessageTextSerializer<ObjectMapper> { - private static final Logger logger = LoggerFactory.getLogger(GraphSONUntypedMessageSerializerV2.class); - private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V2_UNTYPED; +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; @@ -54,21 +54,12 @@ public final class GraphSONUntypedMessageSerializerV2 extends AbstractGraphSONMe * By default this will internally instantiate a {@link GraphSONMapper} and register * a {@link GremlinServerModule} and {@link GraphSONXModuleV2} to the mapper. * - * @see #GraphSONUntypedMessageSerializerV2(GraphSONMapper.Builder) + * @see #GraphSONUntypedMessageSerializerV3(GraphSONMapper.Builder) */ - public GraphSONUntypedMessageSerializerV2() { + public GraphSONUntypedMessageSerializerV3() { super(); } - /** - * 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}. * @@ -76,7 +67,7 @@ public final class GraphSONUntypedMessageSerializerV2 extends AbstractGraphSONMe * this method will automatically register a {@link GremlinServerModule} to the provided * mapper. */ - public GraphSONUntypedMessageSerializerV2(final GraphSONMapper.Builder mapperBuilder) { + public GraphSONUntypedMessageSerializerV3(final GraphSONMapper.Builder mapperBuilder) { super(mapperBuilder); } @@ -87,7 +78,6 @@ public final class GraphSONUntypedMessageSerializerV2 extends AbstractGraphSONMe @Override GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) { - // already set to 2.0 in AbstractGraphSONMessageSerializerV2 return builder.typeInfo(TypeInfo.NO_TYPES).addCustomModule(new GremlinServerModule()); } 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 978e5d6b33..8be6d74848 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 final class SerTokens { 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 d3134c7cad..3aad5e36ee 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 @@ public enum Serializers { GRAPHSON_V1(SerTokens.MIME_GRAPHSON_V1), /** - * GraphSON 2.0 without types. + * GraphSON 1.0 without types. */ GRAPHSON_V1_UNTYPED(SerTokens.MIME_GRAPHSON_V1_UNTYPED), @@ -57,6 +57,11 @@ public enum Serializers { */ GRAPHSON_V3(SerTokens.MIME_GRAPHSON_V3), + /** + * GraphSON 3.0 without types. + */ + GRAPHSON_V3_UNTYPED(SerTokens.MIME_GRAPHSON_V3_UNTYPED), + /** * GraphBinary 1.0. */ @@ -85,6 +90,8 @@ public enum Serializers { 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 d013d6f614..54ce7cd251 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 @@ public class GraphSONMessageSerializerV2Test { @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 @@ public class GraphSONMessageSerializerV2Test { @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 cfa6d77a61..97cce80594 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 @@ public class GraphSONMessageSerializerV3Test { @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 @@ public class GraphSONMessageSerializerV3Test { @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 2c06482040..4eae80ba5a 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 @@ public class GraphSONUntypedMessageSerializerV2Test { @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/GraphSONUntypedMessageSerializerV2Test.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3Test.java similarity index 96% copy from gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV2Test.java copy to gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/GraphSONUntypedMessageSerializerV3Test.java index 2c06482040..65340629b3 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/GraphSONUntypedMessageSerializerV3Test.java @@ -18,16 +18,8 @@ */ package org.apache.tinkerpop.gremlin.util.ser; -import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.UnpooledByteBufAllocator; -import org.apache.tinkerpop.gremlin.structure.io.graphson.AbstractObjectDeserializer; -import org.apache.tinkerpop.gremlin.util.MessageSerializer; -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.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Property; @@ -39,6 +31,9 @@ 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; @@ -51,15 +46,13 @@ import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat; import org.junit.Assert; import org.junit.Test; -import java.awt.Color; +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.Iterator; -import java.util.List; import java.util.Map; import java.util.UUID; @@ -67,7 +60,6 @@ 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.assertNull; import static org.junit.Assert.fail; /** @@ -76,8 +68,8 @@ import static org.junit.Assert.fail; * * @author Stephen Mallette (http://stephen.genoprime.com) */ -public class GraphSONUntypedMessageSerializerV2Test { - public static final GraphSONUntypedMessageSerializerV2 SERIALIZER = new GraphSONUntypedMessageSerializerV2(); +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(); @@ -85,9 +77,9 @@ public class GraphSONUntypedMessageSerializerV2Test { @Test public void shouldConfigureIoRegistry() throws Exception { - final GraphSONUntypedMessageSerializerV1 serializer = new GraphSONUntypedMessageSerializerV1(); + final GraphSONUntypedMessageSerializerV3 serializer = new GraphSONUntypedMessageSerializerV3(); 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/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 e66b825eb4..3622795800 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 @@ public class TinkerGraphGraphSONSerializerV2Test { // 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 42dfc0df2b..c86ba01ca9 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.GraphSONVersion; 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 class GraphSONTranslator<S extends TraversalSource, T extends Traversal.Ad 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"); }