You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2016/06/30 17:34:08 UTC
[39/50] [abbrv] tinkerpop git commit: TINKERPOP-1274: GraphSON 2.0.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0Test.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0Test.java
new file mode 100644
index 0000000..0fea292
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0Test.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.structure.io.graphson;
+
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.time.*;
+import java.util.*;
+
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests non-typed serialization/deserialization for GraphSON 2.0.
+ */
+
+public class GraphSONMapperV2d0Test {
+ private final ObjectMapper mapper = GraphSONMapper.build()
+ .version(GraphSONVersion.V2_0)
+ .typeInfo(GraphSONMapper.TypeInfo.NO_TYPES)
+ .create()
+ .createMapper();
+
+ @Test
+ public void shouldHandleTraversalExplanation() throws Exception {
+ final TraversalExplanation te = __().out().outV().outE().explain();
+ final String json = mapper.writeValueAsString(te);
+ assertEquals("{\"original\":[\"InjectStep([])\",\"VertexStep(OUT,vertex)\",\"EdgeVertexStep(OUT)\",\"VertexStep(OUT,edge)\"],\"intermediate\":[],\"final\":[\"InjectStep([])\",\"VertexStep(OUT,vertex)\",\"EdgeVertexStep(OUT)\",\"VertexStep(OUT,edge)\"]}", json);
+ }
+
+ @Test
+ public void shouldHandleDuration() throws Exception {
+ final Duration o = Duration.ZERO;
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleInstant() throws Exception {
+ final Instant o = Instant.ofEpochMilli(System.currentTimeMillis());
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleLocalDate() throws Exception {
+ final LocalDate o = LocalDate.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleLocalDateTime() throws Exception {
+ final LocalDateTime o = LocalDateTime.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleLocalTime() throws Exception {
+ final LocalTime o = LocalTime.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleMonthDay() throws Exception {
+ final MonthDay o = MonthDay.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleOffsetDateTime() throws Exception {
+ final OffsetDateTime o = OffsetDateTime.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleOffsetTime() throws Exception {
+ final OffsetTime o = OffsetTime.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandlePeriod() throws Exception {
+ final Period o = Period.ofDays(3);
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleYear() throws Exception {
+ final Year o = Year.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleYearMonth() throws Exception {
+ final YearMonth o = YearMonth.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleZonedDateTime() throws Exception {
+ final ZonedDateTime o = ZonedDateTime.now();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldHandleZoneOffset() throws Exception {
+ final ZoneOffset o = ZonedDateTime.now().getOffset();
+ final String json = mapper.writeValueAsString(o);
+ assertEquals("\"" + o.toString() + "\"", json);
+ }
+
+ @Test
+ public void shouldSerializeDeserializeNestedCollectionsAndMapAndTypedCollectionsCorrectly() throws Exception {
+ UUID uuid = UUID.randomUUID();
+ List myList = new ArrayList<>();
+
+ List myList2 = new ArrayList<>();
+ myList2.add(UUID.randomUUID());
+ myList2.add(33L);
+ myList2.add(84);
+ Map map2 = new HashMap<>();
+ map2.put("eheh", UUID.randomUUID());
+ map2.put("normal", "normal");
+ myList2.add(map2);
+
+ Map<String, Object> map1 = new HashMap<>();
+ map1.put("hello", "world");
+ map1.put("test", uuid);
+ map1.put("hehe", myList2);
+ myList.add(map1);
+
+ myList.add("kjkj");
+ myList.add(UUID.randomUUID());
+
+ String json = mapper.writeValueAsString(myList);
+ Object read = mapper.readValue(json, Object.class);
+
+ // Not equals because of type loss
+ assertNotEquals(myList, read);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
new file mode 100644
index 0000000..d0303eb
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV2d0.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import groovy.json.JsonBuilder;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.util.ReferenceCountUtil;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONUtil;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.core.type.TypeReference;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class AbstractGraphSONMessageSerializerV2d0 extends AbstractMessageSerializer {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractGraphSONMessageSerializerV2d0.class);
+
+ protected ObjectMapper mapper;
+
+ protected static final String TOKEN_USE_MAPPER_FROM_GRAPH = "useMapperFromGraph";
+
+ protected final TypeReference<Map<String, Object>> mapTypeReference = new TypeReference<Map<String, Object>>() {
+ };
+
+ public AbstractGraphSONMessageSerializerV2d0() {
+ final GraphSONMapper.Builder builder = configureBuilder(GraphSONMapper.build());
+ mapper = builder.create().createMapper();
+ }
+
+ public AbstractGraphSONMessageSerializerV2d0(final GraphSONMapper mapper) {
+ this.mapper = mapper.createMapper();
+ }
+
+ abstract byte[] obtainHeader();
+
+ abstract GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder);
+
+ @Override
+ public void configure(final Map<String, Object> config, final Map<String, Graph> graphs) {
+ final GraphSONMapper.Builder initialBuilder;
+ final Object graphToUseForMapper = config.get(TOKEN_USE_MAPPER_FROM_GRAPH);
+ if (graphToUseForMapper != null) {
+ if (null == graphs) throw new IllegalStateException(String.format(
+ "No graphs have been provided to the serializer and therefore %s is not a valid configuration", TOKEN_USE_MAPPER_FROM_GRAPH));
+
+ final Graph g = graphs.get(graphToUseForMapper.toString());
+ if (null == g) throw new IllegalStateException(String.format(
+ "There is no graph named [%s] configured to be used in the %s setting",
+ graphToUseForMapper, TOKEN_USE_MAPPER_FROM_GRAPH));
+
+ // a graph was found so use the mapper it constructs. this allows graphson to be auto-configured with any
+ // custom classes that the implementation allows for
+ initialBuilder = g.io(GraphSONIo.build()).mapper();
+ } else {
+ // no graph was supplied so just use the default - this will likely be the case when using a graph
+ // with no custom classes or a situation where the user needs complete control like when using two
+ // distinct implementations each with their own custom classes.
+ initialBuilder = GraphSONMapper.build();
+ }
+
+ addIoRegistries(config, initialBuilder);
+
+ mapper = configureBuilder(initialBuilder).create().createMapper();
+ }
+
+ @Override
+ public ByteBuf serializeResponseAsBinary(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+ ByteBuf encodedMessage = null;
+ try {
+ final byte[] payload = mapper.writeValueAsBytes(responseMessage);
+ encodedMessage = allocator.buffer(payload.length);
+ encodedMessage.writeBytes(payload);
+
+ return encodedMessage;
+ } catch (Exception ex) {
+ if (encodedMessage != null) ReferenceCountUtil.release(encodedMessage);
+
+ logger.warn("Response [{}] could not be serialized by {}.", responseMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public ByteBuf serializeRequestAsBinary(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+ ByteBuf encodedMessage = null;
+ try {
+ final byte[] header = obtainHeader();
+ final byte[] payload = mapper.writeValueAsBytes(requestMessage);
+
+ encodedMessage = allocator.buffer(header.length + payload.length);
+ encodedMessage.writeBytes(header);
+ encodedMessage.writeBytes(payload);
+
+ return encodedMessage;
+ } catch (Exception ex) {
+ if (encodedMessage != null) ReferenceCountUtil.release(encodedMessage);
+
+ logger.warn("Request [{}] could not be serialized by {}.", requestMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public RequestMessage deserializeRequest(final ByteBuf msg) throws SerializationException {
+ try {
+ final byte[] payload = new byte[msg.readableBytes()];
+ msg.readBytes(payload);
+ return mapper.readValue(payload, RequestMessage.class);
+ } catch (Exception ex) {
+ logger.warn("Request [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public ResponseMessage deserializeResponse(final ByteBuf msg) throws SerializationException {
+ try {
+ final byte[] payload = new byte[msg.readableBytes()];
+ msg.readBytes(payload);
+ final Map<String, Object> responseData = mapper.readValue(payload, mapTypeReference);
+ final Map<String, Object> status = (Map<String, Object>) responseData.get(SerTokens.TOKEN_STATUS);
+ final Map<String, Object> result = (Map<String, Object>) responseData.get(SerTokens.TOKEN_RESULT);
+ return ResponseMessage.build(UUID.fromString(responseData.get(SerTokens.TOKEN_REQUEST).toString()))
+ .code(ResponseStatusCode.getFromValue((Integer) status.get(SerTokens.TOKEN_CODE)))
+ .statusMessage(status.get(SerTokens.TOKEN_MESSAGE).toString())
+ .statusAttributes((Map<String, Object>) status.get(SerTokens.TOKEN_ATTRIBUTES))
+ .result(result.get(SerTokens.TOKEN_DATA))
+ .responseMetaData((Map<String, Object>) result.get(SerTokens.TOKEN_META))
+ .create();
+ } catch (Exception ex) {
+ logger.warn("Response [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ public final static class GremlinServerModule extends SimpleModule {
+ public GremlinServerModule() {
+ super("graphson-gremlin-server");
+ addSerializer(JsonBuilder.class, new JsonBuilderJacksonSerializer());
+ addSerializer(ResponseMessage.class, new ResponseMessageSerializer());
+ }
+ }
+
+ public final static class JsonBuilderJacksonSerializer extends StdSerializer<JsonBuilder> {
+ public JsonBuilderJacksonSerializer() {
+ super(JsonBuilder.class);
+ }
+
+ @Override
+ public void serialize(final JsonBuilder json, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
+ throws IOException, JsonGenerationException {
+ // the JSON from the builder will already be started/ended as array or object...just need to surround it
+ // with appropriate chars to fit into the serialization pattern.
+ jsonGenerator.writeRaw(":");
+ jsonGenerator.writeRaw(json.toString());
+ jsonGenerator.writeRaw(",");
+ }
+ }
+
+ public final static class ResponseMessageSerializer extends StdSerializer<ResponseMessage> {
+ public ResponseMessageSerializer() {
+ super(ResponseMessage.class);
+ }
+
+ @Override
+ public void serialize(final ResponseMessage responseMessage, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider) throws IOException {
+ ser(responseMessage, jsonGenerator, serializerProvider, null);
+ }
+
+ @Override
+ public void serializeWithType(final ResponseMessage responseMessage, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider,
+ final TypeSerializer typeSerializer) throws IOException {
+ ser(responseMessage, jsonGenerator, serializerProvider, typeSerializer);
+ }
+
+ public void ser(final ResponseMessage responseMessage, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider,
+ final TypeSerializer typeSerializer) throws IOException {
+ GraphSONUtil.writeStartObject(responseMessage, jsonGenerator, typeSerializer);
+
+ jsonGenerator.writeStringField(SerTokens.TOKEN_REQUEST, responseMessage.getRequestId() != null ? responseMessage.getRequestId().toString() : null);
+ jsonGenerator.writeFieldName(SerTokens.TOKEN_STATUS);
+
+ GraphSONUtil.writeStartObject(responseMessage, jsonGenerator, typeSerializer);
+ jsonGenerator.writeStringField(SerTokens.TOKEN_MESSAGE, responseMessage.getStatus().getMessage());
+ jsonGenerator.writeNumberField(SerTokens.TOKEN_CODE, responseMessage.getStatus().getCode().getValue());
+ jsonGenerator.writeObjectField(SerTokens.TOKEN_ATTRIBUTES, responseMessage.getStatus().getAttributes());
+ GraphSONUtil.writeEndObject(responseMessage, jsonGenerator, typeSerializer);
+
+ jsonGenerator.writeFieldName(SerTokens.TOKEN_RESULT);
+
+ GraphSONUtil.writeStartObject(responseMessage, jsonGenerator, typeSerializer);
+
+ if (null == responseMessage.getResult().getData())
+ {
+ jsonGenerator.writeNullField(SerTokens.TOKEN_DATA);
+ }
+ else
+ {
+ jsonGenerator.writeFieldName(SerTokens.TOKEN_DATA);
+ Object result = responseMessage.getResult().getData();
+ serializerProvider.findTypedValueSerializer(result.getClass(), true, null).serialize(result, jsonGenerator, serializerProvider);
+ }
+
+ jsonGenerator.writeObjectField(SerTokens.TOKEN_META, responseMessage.getResult().getMeta());
+ GraphSONUtil.writeEndObject(responseMessage, jsonGenerator, typeSerializer);
+
+ GraphSONUtil.writeEndObject(responseMessage, jsonGenerator, typeSerializer);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0.java
new file mode 100644
index 0000000..3c2fd3f
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Serialize results to JSON with version 2.0.x schema.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class GraphSONMessageSerializerGremlinV2d0 extends AbstractGraphSONMessageSerializerV2d0 {
+
+ private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V1D0;
+
+ private static byte[] header;
+
+ static {
+ final ByteBuffer buffer = ByteBuffer.allocate(MIME_TYPE.length() + 1);
+ buffer.put((byte) MIME_TYPE.length());
+ buffer.put(MIME_TYPE.getBytes());
+ header = buffer.array();
+ }
+
+ public GraphSONMessageSerializerGremlinV2d0() {
+ super();
+ }
+
+ public GraphSONMessageSerializerGremlinV2d0(final GraphSONMapper mapper) {
+ super(mapper);
+ }
+
+ @Override
+ public String[] mimeTypesSupported() {
+ return new String[]{MIME_TYPE};
+ }
+
+ @Override
+ byte[] obtainHeader() {
+ return header;
+ }
+
+ @Override
+ GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) {
+ return builder.version(GraphSONVersion.V2_0)
+ .addCustomModule(new GremlinServerModule())
+ .typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
new file mode 100644
index 0000000..85d1c5b
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Serialize results to JSON with version 2.0.x schema.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class GraphSONMessageSerializerV2d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer {
+ private static final Logger logger = LoggerFactory.getLogger(GraphSONMessageSerializerV2d0.class);
+ private static final String MIME_TYPE = SerTokens.MIME_JSON;
+
+ private static byte[] header;
+
+ static {
+ final ByteBuffer buffer = ByteBuffer.allocate(MIME_TYPE.length() + 1);
+ buffer.put((byte) MIME_TYPE.length());
+ buffer.put(MIME_TYPE.getBytes());
+ header = buffer.array();
+ }
+
+ public GraphSONMessageSerializerV2d0() {
+ super();
+ }
+
+ public GraphSONMessageSerializerV2d0(final GraphSONMapper mapper) {
+ super(mapper);
+ }
+
+ @Override
+ public String[] mimeTypesSupported() {
+ return new String[]{MIME_TYPE};
+ }
+
+ @Override
+ GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) {
+ return builder.version(GraphSONVersion.V2_0)
+ .addCustomModule(new GremlinServerModule())
+ .typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES);
+ }
+
+ @Override
+ byte[] obtainHeader() {
+ return header;
+ }
+
+ @Override
+ public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+ try {
+ final Map<String, Object> responseData = mapper.readValue(msg, mapTypeReference);
+ final Map<String, Object> status = (Map<String, Object>) responseData.get(SerTokens.TOKEN_STATUS);
+ final Map<String, Object> result = (Map<String, Object>) responseData.get(SerTokens.TOKEN_RESULT);
+ return ResponseMessage.build(UUID.fromString(responseData.get(SerTokens.TOKEN_REQUEST).toString()))
+ .code(ResponseStatusCode.getFromValue((Integer) status.get(SerTokens.TOKEN_CODE)))
+ .statusMessage(status.get(SerTokens.TOKEN_MESSAGE).toString())
+ .statusAttributes((Map<String, Object>) status.get(SerTokens.TOKEN_ATTRIBUTES))
+ .result(result.get(SerTokens.TOKEN_DATA))
+ .responseMetaData((Map<String, Object>) result.get(SerTokens.TOKEN_META))
+ .create();
+ } catch (Exception ex) {
+ logger.warn("Response [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException {
+ try {
+ return mapper.writeValueAsString(responseMessage);
+ } catch (Exception ex) {
+ logger.warn("Response [{}] could not be serialized by {}.", responseMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+ try {
+ return mapper.readValue(msg, RequestMessage.class);
+ } catch (Exception ex) {
+ logger.warn("Request [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+
+ @Override
+ public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException {
+ try {
+ return mapper.writeValueAsString(requestMessage);
+ } catch (Exception ex) {
+ logger.warn("Request [{}] could not be serialized by {}.", requestMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+ throw new SerializationException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
new file mode 100644
index 0000000..7f21586
--- /dev/null
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV2d0Test.java
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.*;
+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.shaded.jackson.databind.util.StdDateFormat;
+import org.junit.Test;
+
+import java.util.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Serializer tests that cover non-lossy serialization/deserialization methods for GraphSONMessage.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GraphSONMessageSerializerGremlinV2d0Test {
+ private UUID requestId = UUID.fromString("6457272A-4018-4538-B9AE-08DD5DDC0AA1");
+ private ResponseMessage.Builder responseMessageBuilder = ResponseMessage.build(requestId);
+ private static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
+
+ public MessageSerializer serializer = new GraphSONMessageSerializerGremlinV2d0();
+
+ @Test
+ public void shouldSerializeIterable() throws Exception {
+ final ArrayList<Integer> list = new ArrayList<>();
+ list.add(1);
+ list.add(100);
+
+ final ResponseMessage response = convert(list);
+ assertCommon(response);
+
+ final List<Integer> deserializedFunList = (List<Integer>) response.getResult().getData();
+ assertEquals(2, deserializedFunList.size());
+ assertEquals(new Integer(1), deserializedFunList.get(0));
+ assertEquals(new Integer(100), deserializedFunList.get(1));
+ }
+
+ @Test
+ public void shouldSerializeIterableWithNull() throws Exception {
+ final ArrayList<Integer> list = new ArrayList<>();
+ list.add(1);
+ list.add(null);
+ list.add(100);
+
+ final ResponseMessage response = convert(list);
+ assertCommon(response);
+
+ final List<Integer> deserializedFunList = (List<Integer>) response.getResult().getData();
+ assertEquals(3, deserializedFunList.size());
+ assertEquals(new Integer(1), deserializedFunList.get(0));
+ assertNull(deserializedFunList.get(1));
+ assertEquals(new Integer(100), deserializedFunList.get(2));
+ }
+
+ @Test
+ public void shouldSerializeMap() throws Exception {
+ final Map<String, Object> map = new HashMap<>();
+ final Map<String, String> innerMap = new HashMap<>();
+ innerMap.put("a", "b");
+
+ map.put("x", 1);
+ map.put("y", "some");
+ map.put("z", innerMap);
+
+ final ResponseMessage response = convert(map);
+ assertCommon(response);
+
+ final Map<String, Object> deserializedMap = (Map<String, Object>) response.getResult().getData();
+ assertEquals(3, deserializedMap.size());
+ assertEquals(1, deserializedMap.get("x"));
+ assertEquals("some", deserializedMap.get("y"));
+
+ final Map<String, String> deserializedInnerMap = (Map<String, String>) deserializedMap.get("z");
+ assertEquals(1, deserializedInnerMap.size());
+ assertEquals("b", deserializedInnerMap.get("a"));
+ }
+
+ @Test
+ public void shouldSerializeMapEntries() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v1 = graph.addVertex();
+ final Date d = new Date();
+
+ final Map<Object, Object> map = new HashMap<>();
+ map.put("x", 1);
+ map.put(v1, 100);
+ map.put(d, "test");
+
+ final ResponseMessage response = convert(IteratorUtils.asList(map.entrySet()));
+ assertCommon(response);
+
+ final List<Map<String, Object>> deserializedEntries = (List<Map<String, Object>>) response.getResult().getData();
+ assertEquals(3, deserializedEntries.size());
+ deserializedEntries.forEach(e -> {
+ if (e.containsKey("x"))
+ assertEquals(1, e.get("x"));
+ else if (e.containsKey(v1.id().toString()))
+ assertEquals(100, e.get(v1.id().toString()));
+ else if (e.containsKey(StdDateFormat.instance.format(d)))
+ assertEquals("test", e.get(StdDateFormat.instance.format(d)));
+ else
+ fail("Map entries contains a key that is not part of what was serialized");
+ });
+ }
+
+ @Test
+ public void shouldSerializeEdge() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v1 = graph.addVertex();
+ final Vertex v2 = graph.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Edge> iterable = IteratorUtils.list(graph.edges());
+
+ final ResponseMessage response = convert(iterable);
+ assertCommon(response);
+
+ final List<Map<String, Object>> edgeList = (List<Map<String, Object>>) response.getResult().getData();
+ assertEquals(1, edgeList.size());
+
+ final Map<String, Object> deserializedEdge = edgeList.get(0);
+ assertEquals(e.id(), deserializedEdge.get(GraphSONTokens.ID));
+ assertEquals(v1.id(), deserializedEdge.get(GraphSONTokens.OUT));
+ assertEquals(v2.id(), deserializedEdge.get(GraphSONTokens.IN));
+ assertEquals(v1.label(), deserializedEdge.get(GraphSONTokens.OUT_LABEL));
+ assertEquals(v2.label(), deserializedEdge.get(GraphSONTokens.IN_LABEL));
+ assertEquals(e.label(), deserializedEdge.get(GraphSONTokens.LABEL));
+ assertEquals(GraphSONTokens.EDGE, deserializedEdge.get(GraphSONTokens.TYPE));
+
+ final Map<String, Object> properties = (Map<String, Object>) deserializedEdge.get(GraphSONTokens.PROPERTIES);
+ assertNotNull(properties);
+ assertEquals(123, properties.get("abc"));
+
+ }
+
+ @Test
+ public void shouldSerializeEdgeProperty() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v1 = graph.addVertex();
+ final Vertex v2 = graph.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
+ final ResponseMessage response = convert(iterable);
+ assertCommon(response);
+
+ final List<Map<String, Object>> propertyList = (List<Map<String, Object>>) response.getResult().getData();
+ assertEquals(1, propertyList.size());
+ assertEquals(123, propertyList.get(0).get("value"));
+ }
+
+ @Test
+ public void shouldSerializeVertexWithEmbeddedMap() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v = graph.addVertex();
+ final Map<String, Object> map = new HashMap<>();
+ map.put("x", 500);
+ map.put("y", "some");
+
+ final ArrayList<Object> friends = new ArrayList<>();
+ friends.add("x");
+ friends.add(5);
+ friends.add(map);
+
+ v.property(VertexProperty.Cardinality.single, "friends", friends);
+
+ final List list = IteratorUtils.list(graph.vertices());
+
+ final ResponseMessage response = convert(list);
+ assertCommon(response);
+
+ final List<Map<String, Object>> vertexList = (List<Map<String, Object>>) response.getResult().getData();
+ assertEquals(1, vertexList.size());
+
+ final Map<String, Object> deserializedVertex = vertexList.get(0);
+ assertEquals(v.id(), deserializedVertex.get(GraphSONTokens.ID));
+ assertEquals(Vertex.DEFAULT_LABEL, deserializedVertex.get(GraphSONTokens.LABEL));
+
+ final Map<String, Object> properties = ((Map<String, Object>) deserializedVertex.get(GraphSONTokens.PROPERTIES));
+ assertEquals(1, properties.size());
+
+ final List<Map<String,Object>> friendsProperties = (List<Map<String,Object>>) properties.get("friends");
+ assertEquals(1, friendsProperties.size());
+
+ final List<Object> deserializedInnerList = (List<Object>) friendsProperties.get(0).get(GraphSONTokens.VALUE);
+ assertEquals(3, deserializedInnerList.size());
+ assertEquals("x", deserializedInnerList.get(0));
+ assertEquals(5, deserializedInnerList.get(1));
+
+ final Map<String, Object> deserializedInnerInnerMap = (Map<String, Object>) deserializedInnerList.get(2);
+ assertEquals(2, deserializedInnerInnerMap.size());
+ assertEquals(500, deserializedInnerInnerMap.get("x"));
+ assertEquals("some", deserializedInnerInnerMap.get("y"));
+ }
+
+ @Test
+ public void shouldSerializeToJsonMapWithElementForKey() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createClassic();
+ final GraphTraversalSource g = graph.traversal();
+ final Map<Vertex, Integer> map = new HashMap<>();
+ map.put(g.V().has("name", "marko").next(), 1000);
+
+ final ResponseMessage response = convert(map);
+ assertCommon(response);
+
+ final Map<String, Integer> deserializedMap = (Map<String, Integer>) response.getResult().getData();
+ assertEquals(1, deserializedMap.size());
+
+ // with no embedded types the key (which is a vertex) simply serializes out to an id
+ // {"result":{"1":1000},"code":200,"requestId":"2d62161b-9544-4f39-af44-62ec49f9a595","type":0}
+ assertEquals(new Integer(1000), deserializedMap.get("1"));
+ }
+
+ @Test
+ public void shouldSerializeToJsonTree() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createClassic();
+ final GraphTraversalSource g = graph.traversal();
+ final Map t = g.V(1).out().properties("name").tree().next();
+
+ final ResponseMessage response = convert(t);
+ assertCommon(response);
+
+ final Map<String, Map<String, Map>> deserializedMap = (Map<String, Map<String, Map>>) response.getResult().getData();
+
+ assertEquals(1, deserializedMap.size());
+
+ //check the first object and it's properties
+ Map<String,Object> vertex = deserializedMap.get("1").get("key");
+ Map<String,List<Map>> vertexProperties = (Map<String, List<Map>>)vertex.get("properties");
+ assertEquals(1, (int)vertex.get("id"));
+ assertEquals("marko", vertexProperties.get("name").get(0).get("value"));
+
+ //check objects tree structure
+ //check Vertex property
+ Map<String, Map<String, Map>> subTreeMap = deserializedMap.get("1").get("value");
+ Map<String, Map<String, Map>> subTreeMap2 = subTreeMap.get("2").get("value");
+ Map<String, String> vertexPropertiesDeep = subTreeMap2.get("3").get("key");
+ assertEquals("vadas", vertexPropertiesDeep.get("value"));
+ assertEquals("name", vertexPropertiesDeep.get("label"));
+
+ // check subitem
+ Map<String,Object> vertex2 = subTreeMap.get("3").get("key");
+ Map<String,List<Map>> vertexProperties2 = (Map<String, List<Map>>)vertex2.get("properties");
+
+ assertEquals("lop", vertexProperties2.get("name").get(0).get("value"));
+ }
+
+ @Test
+ public void shouldSerializeFullResponseMessage() throws Exception {
+ final UUID id = UUID.randomUUID();
+
+ final Map<String, Object> metaData = new HashMap<>();
+ metaData.put("test", "this");
+ metaData.put("one", 1);
+
+ final Map<String, Object> attributes = new HashMap<>();
+ attributes.put("test", "that");
+ attributes.put("two", 2);
+
+ final ResponseMessage response = ResponseMessage.build(id)
+ .responseMetaData(metaData)
+ .code(ResponseStatusCode.SUCCESS)
+ .result("some-result")
+ .statusAttributes(attributes)
+ .statusMessage("worked")
+ .create();
+
+ final ByteBuf bb = serializer.serializeResponseAsBinary(response, allocator);
+ final ResponseMessage deserialized = serializer.deserializeResponse(bb);
+
+ assertEquals(id, deserialized.getRequestId());
+ assertEquals("this", deserialized.getResult().getMeta().get("test"));
+ assertEquals(1, deserialized.getResult().getMeta().get("one"));
+ assertEquals("some-result", deserialized.getResult().getData());
+ assertEquals("that", deserialized.getStatus().getAttributes().get("test"));
+ assertEquals(2, deserialized.getStatus().getAttributes().get("two"));
+ assertEquals(ResponseStatusCode.SUCCESS.getValue(), deserialized.getStatus().getCode().getValue());
+ assertEquals("worked", deserialized.getStatus().getMessage());
+ }
+
+ private void assertCommon(final ResponseMessage response) {
+ assertEquals(requestId, response.getRequestId());
+ assertEquals(ResponseStatusCode.SUCCESS, response.getStatus().getCode());
+ }
+
+ private ResponseMessage convert(final Object toSerialize) throws SerializationException {
+ final ByteBuf bb = serializer.serializeResponseAsBinary(responseMessageBuilder.result(toSerialize).create(), allocator);
+ return serializer.deserializeResponse(bb);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
new file mode 100644
index 0000000..0e07d44
--- /dev/null
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.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.*;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
+import org.apache.tinkerpop.shaded.jackson.databind.node.NullNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
+import org.junit.Test;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.*;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+
+/**
+ * These tests focus on message serialization and not "result" serialization as test specific to results (e.g.
+ * vertices, edges, annotated values, etc.) are handled in the IO packages.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GraphSONMessageSerializerV2d0Test {
+
+ public static final GraphSONMessageSerializerV2d0 SERIALIZER = new GraphSONMessageSerializerV2d0();
+ private static final RequestMessage msg = RequestMessage.build("op")
+ .overrideRequestId(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595")).create();
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ @Test
+ public void shouldConfigureIoRegistry() throws Exception {
+ final GraphSONMessageSerializerV1d0 serializer = new GraphSONMessageSerializerV1d0();
+ final Map<String, Object> config = new HashMap<String, Object>() {{
+ put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
+ }};
+
+ serializer.configure(config, null);
+
+ final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
+ .result(Color.RED).create();
+ final String results = serializer.serializeResponseAsString(toSerialize);
+ final JsonNode json = mapper.readTree(results);
+ assertNotNull(json);
+ assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
+ }
+
+ @Test
+ public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
+ final ResponseMessage message = ResponseMessage.build(msg).create();
+ final String results = SERIALIZER.serializeResponseAsString(message);
+ final JsonNode json = mapper.readTree(results);
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.path(SerTokens.TOKEN_REQUEST).asText());
+ assertEquals(NullNode.getInstance(), json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA));
+ }
+
+ @Test
+ public void shouldSerializeToJsonIterable() throws Exception {
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(2, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals("y", converted.get(1).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIterator() throws Exception {
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(2, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals("y", converted.get(1).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIteratorNullElement() throws Exception {
+
+ final ArrayList<FunObject> funList = new ArrayList<>();
+ funList.add(new FunObject("x"));
+ funList.add(null);
+ funList.add(new FunObject("y"));
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertEquals(3, converted.size());
+
+ assertEquals("x", converted.get(0).asText());
+ assertEquals(NullNode.getInstance(), converted.get(1));
+ assertEquals("y", converted.get(2).asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonMap() throws Exception {
+ final Map<String, Object> map = new HashMap<>();
+ final Map<String, String> innerMap = new HashMap<>();
+ innerMap.put("a", "b");
+
+ map.put("x", new FunObject("x"));
+ map.put("y", "some");
+ map.put("z", innerMap);
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(jsonObject);
+ assertEquals("some", jsonObject.get("y").asText());
+ assertEquals("x", jsonObject.get("x").asText());
+
+ final JsonNode innerJsonObject = jsonObject.get("z");
+ assertNotNull(innerJsonObject);
+ assertEquals("b", innerJsonObject.get("a").asText());
+ }
+
+ @Test
+ public void shouldShouldSerializeMapEntries() throws Exception {
+ final Graph graph = TinkerGraph.open();
+ final Vertex v1 = graph.addVertex();
+ final Date d = new Date();
+
+ final Map<Object, Object> map = new HashMap<>();
+ map.put("x", 1);
+ map.put(v1, 100);
+ map.put(d, "test");
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+ jsonObject.elements().forEachRemaining(e -> {
+ if (e.has("x"))
+ assertEquals(1, e.get("x").asInt());
+ else if (e.has(v1.id().toString()))
+ assertEquals(100, e.get(v1.id().toString()).asInt());
+ else if (e.has(StdDateFormat.instance.format(d)))
+ assertEquals("test", e.get(StdDateFormat.instance.format(d)).asText());
+ else
+ fail("Map entries contains a key that is not part of what was serialized");
+ });
+ }
+
+ @Test
+ public void shouldSerializeEdge() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v1 = g.addVertex();
+ final Vertex v2 = g.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Edge> iterable = IteratorUtils.list(g.edges());
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode edgeAsJson = converted.get(0);
+ assertNotNull(edgeAsJson);
+
+ assertEquals(((Long) e.id()).longValue(), edgeAsJson.get(GraphSONTokens.ID).get(1).asLong()); // lossy
+ assertEquals(((Long) v1.id()).longValue(), edgeAsJson.get(GraphSONTokens.OUT).get(1).asLong());// lossy
+ assertEquals(((Long) v2.id()).longValue(), edgeAsJson.get(GraphSONTokens.IN).get(1).asLong()); // lossy
+ assertEquals(e.label(), edgeAsJson.get(GraphSONTokens.LABEL).asText());
+ assertEquals(GraphSONTokens.EDGE, edgeAsJson.get(GraphSONTokens.TYPE).asText());
+
+ final JsonNode properties = edgeAsJson.get(GraphSONTokens.PROPERTIES);
+ assertNotNull(properties);
+ assertEquals(123, properties.get("abc").asInt());
+ }
+
+ @Test
+ public void shouldSerializeEdgeProperty() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v1 = g.addVertex();
+ final Vertex v2 = g.addVertex();
+ final Edge e = v1.addEdge("test", v2);
+ e.property("abc", 123);
+
+ final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode propertyAsJson = converted.get(0);
+ assertNotNull(propertyAsJson);
+
+ assertEquals(123, propertyAsJson.get("value").asInt());
+ }
+
+ @Test
+ public void shouldSerializeToJsonIteratorWithEmbeddedMap() throws Exception {
+ final Graph g = TinkerGraph.open();
+ final Vertex v = g.addVertex();
+ final Map<String, Object> map = new HashMap<>();
+ map.put("x", 500);
+ map.put("y", "some");
+
+ final ArrayList<Object> friends = new ArrayList<>();
+ friends.add("x");
+ friends.add(5);
+ friends.add(map);
+
+ v.property(VertexProperty.Cardinality.single, "friends", friends);
+
+ final Iterable iterable = IteratorUtils.list(g.vertices());
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+ assertEquals(1, converted.size());
+
+ final JsonNode vertexAsJson = converted.get(0);
+ assertNotNull(vertexAsJson);
+
+ final JsonNode properties = vertexAsJson.get(GraphSONTokens.PROPERTIES);
+ assertNotNull(properties);
+ assertEquals(1, properties.size());
+
+ final JsonNode friendProperties = properties.get("friends");
+ assertEquals(1, friendProperties.size());
+ final JsonNode friendsProperty = friendProperties.get(0);
+ assertNotNull(friendsProperty);
+ assertEquals(3, friends.size());
+
+ final String object1 = friendsProperty.get(GraphSONTokens.VALUE).get(0).asText();
+ assertEquals("x", object1);
+
+ final int object2 = friendsProperty.get(GraphSONTokens.VALUE).get(1).asInt();
+ assertEquals(5, object2);
+
+ final JsonNode object3 = friendsProperty.get(GraphSONTokens.VALUE).get(2);
+ assertEquals(500, object3.get("x").asInt());
+ assertEquals("some", object3.get("y").asText());
+ }
+
+ @Test
+ public void shouldSerializeToJsonMapWithElementForKey() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createClassic();
+ final GraphTraversalSource g = graph.traversal();
+ final Map<Vertex, Integer> map = new HashMap<>();
+ map.put(g.V().has("name", "marko").next(), 1000);
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+ assertNotNull(converted);
+
+ // with no embedded types the key (which is a vertex) simply serializes out to an id
+ // {"result":{"1":1000},"code":200,"requestId":"2d62161b-9544-4f39-af44-62ec49f9a595","type":0}
+ assertEquals(1000, converted.get("1").asInt());
+ }
+
+ @Test
+ public void shouldDeserializeRequestNicelyWithNoArgs() throws Exception {
+ final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+ final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\"}", request));
+ assertEquals(request, m.getRequestId());
+ assertEquals("eval", m.getOp());
+ assertNotNull(m.getArgs());
+ assertEquals(0, m.getArgs().size());
+ }
+
+ @Test
+ public void shouldDeserializeRequestNicelyWithArgs() throws Exception {
+ final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+ final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}", request));
+ assertEquals(request, m.getRequestId());
+ assertEquals("eval", m.getOp());
+ assertNotNull(m.getArgs());
+ assertEquals("y", m.getArgs().get("x"));
+ }
+
+ @Test(expected = SerializationException.class)
+ public void shouldDeserializeRequestParseMessage() throws Exception {
+ SERIALIZER.deserializeRequest("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}");
+ }
+
+ @Test
+ public void shouldSerializeFullResponseMessage() throws Exception {
+ final UUID id = UUID.randomUUID();
+
+ final Map<String, Object> metaData = new HashMap<>();
+ metaData.put("test", "this");
+ metaData.put("one", 1);
+
+ final Map<String, Object> attributes = new HashMap<>();
+ attributes.put("test", "that");
+ attributes.put("two", 2);
+
+ final ResponseMessage response = ResponseMessage.build(id)
+ .responseMetaData(metaData)
+ .code(ResponseStatusCode.SUCCESS)
+ .result("some-result")
+ .statusAttributes(attributes)
+ .statusMessage("worked")
+ .create();
+
+ final String results = SERIALIZER.serializeResponseAsString(response);
+ final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
+
+ assertEquals(id, deserialized.getRequestId());
+ assertEquals("this", deserialized.getResult().getMeta().get("test"));
+ assertEquals(1, deserialized.getResult().getMeta().get("one"));
+ assertEquals("some-result", deserialized.getResult().getData());
+ assertEquals("that", deserialized.getStatus().getAttributes().get("test"));
+ assertEquals(2, deserialized.getStatus().getAttributes().get("two"));
+ assertEquals(ResponseStatusCode.SUCCESS.getValue(), deserialized.getStatus().getCode().getValue());
+ assertEquals("worked", deserialized.getStatus().getMessage());
+ }
+
+ @Test
+ public void shouldSerializeToJsonTree() throws Exception {
+ final TinkerGraph graph = TinkerFactory.createClassic();
+ final GraphTraversalSource g = graph.traversal();
+ final Tree t = g.V(1).out().properties("name").tree().next();
+
+
+ final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create());
+
+ final JsonNode json = mapper.readTree(results);
+
+ assertNotNull(json);
+ assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+ final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+ assertNotNull(converted);
+
+ //check the first object and it's properties
+ assertEquals(1, converted.get("1").get("key").get("id").asInt());
+ assertEquals("marko", converted.get("1").get("key").get("properties").get("name").get(0).get("value").asText());
+
+ //check objects tree structure
+ //check Vertex property
+ assertEquals("vadas", converted.get("1")
+ .get("value")
+ .get("2")
+ .get("value")
+ .get("3").get("key").get("value").asText());
+ assertEquals("name", converted.get("1")
+ .get("value")
+ .get("2")
+ .get("value")
+ .get("3").get("key").get("label").asText());
+
+ // check subitem
+ assertEquals("lop", converted.get("1")
+ .get("value")
+ .get("3")
+ .get("key")
+ .get("properties").get("name").get(0).get("value").asText());
+ }
+
+ private static class FunObject {
+ private String val;
+
+ public FunObject(String val) {
+ this.val = val;
+ }
+
+ public String toString() {
+ return this.val;
+ }
+ }
+
+ public static class ColorIoRegistry extends AbstractIoRegistry {
+ public ColorIoRegistry() {
+ register(GraphSONIo.class, null, new ColorSimpleModule());
+ }
+ }
+
+ public static class ColorSimpleModule extends SimpleModule {
+ public ColorSimpleModule() {
+ super("color-fun");
+ addSerializer(Color.class, new ColorSerializer());
+
+ }
+ }
+
+ public static class ColorSerializer extends StdSerializer<Color> {
+ public ColorSerializer() {
+ super(Color.class);
+ }
+
+ @Override
+ public void serialize(final Color color, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider) throws IOException, JsonGenerationException {
+ jsonGenerator.writeBoolean(color.equals(Color.RED));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
new file mode 100644
index 0000000..9923905
--- /dev/null
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.tinkergraph.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONUtil;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TinkerPopJacksonModule;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoIo;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoReader;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoWriter;
+import org.apache.tinkerpop.gremlin.structure.util.Attachable;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
+import org.apache.tinkerpop.shaded.jackson.core.JsonProcessingException;
+import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer;
+import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+import org.apache.tinkerpop.shaded.kryo.Kryo;
+import org.apache.tinkerpop.shaded.kryo.Serializer;
+import org.apache.tinkerpop.shaded.kryo.io.Input;
+import org.apache.tinkerpop.shaded.kryo.io.Output;
+import org.javatuples.Pair;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of the {@link org.apache.tinkerpop.gremlin.structure.io.IoRegistry} interface that provides serializers with custom configurations for
+ * implementation specific classes that might need to be serialized. This registry allows a {@link org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph} to
+ * be serialized directly which is useful for moving small graphs around on the network.
+ * <p/>
+ * Most providers need not implement this kind of custom serializer as they will deal with much larger graphs that
+ * wouldn't be practical to serialize in this fashion. This is a bit of a special case for TinkerGraph given its
+ * in-memory status. Typical implementations would create serializers for a complex vertex identifier or a
+ * custom data class like a "geographic point".
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class TinkerIoRegistryV2d0 extends AbstractIoRegistry {
+
+ private static final TinkerIoRegistryV2d0 INSTANCE = new TinkerIoRegistryV2d0();
+
+ private TinkerIoRegistryV2d0() {
+ register(GryoIo.class, TinkerGraph.class, new TinkerGraphGryoSerializer());
+ register(GraphSONIo.class, null, new TinkerModuleV2d0());
+ }
+
+ public static TinkerIoRegistryV2d0 getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Provides a method to serialize an entire {@link org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph} into itself for Gryo. This is useful when
+ * shipping small graphs around through Gremlin Server. Reuses the existing Kryo instance for serialization.
+ */
+ final static class TinkerGraphGryoSerializer extends Serializer<TinkerGraph> {
+ @Override
+ public void write(final Kryo kryo, final Output output, final TinkerGraph graph) {
+ try (final ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+ GryoWriter.build().mapper(() -> kryo).create().writeGraph(stream, graph);
+ final byte[] bytes = stream.toByteArray();
+ output.writeInt(bytes.length);
+ output.write(bytes);
+ } catch (Exception io) {
+ throw new RuntimeException(io);
+ }
+ }
+
+ @Override
+ public TinkerGraph read(final Kryo kryo, final Input input, final Class<TinkerGraph> tinkerGraphClass) {
+ final TinkerGraph graph = TinkerGraph.open();
+ final int len = input.readInt();
+ final byte[] bytes = input.readBytes(len);
+ try (final ByteArrayInputStream stream = new ByteArrayInputStream(bytes)) {
+ GryoReader.build().mapper(() -> kryo).create().readGraph(stream, graph);
+ } catch (Exception io) {
+ throw new RuntimeException(io);
+ }
+
+ return graph;
+ }
+ }
+
+ /**
+ * Provides a method to serialize an entire {@link org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph} into itself for GraphSON. This is useful when
+ * shipping small graphs around through Gremlin Server.
+ */
+ final static class TinkerModuleV2d0 extends TinkerPopJacksonModule {
+ public TinkerModuleV2d0() {
+ super("tinkergraph-2.0");
+ addSerializer(TinkerGraph.class, new TinkerGraphJacksonSerializer());
+ addDeserializer(TinkerGraph.class, new TinkerGraphJacksonDeserializer());
+ }
+ }
+
+ /**
+ * Serializes the graph into an edge list format. Edge list is a better choices than adjacency list (which is
+ * typically standard from the {@link org.apache.tinkerpop.gremlin.structure.io.GraphReader} and {@link org.apache.tinkerpop.gremlin.structure.io.GraphWriter} perspective) in this case because
+ * the use case for this isn't around massive graphs. The use case is for "small" subgraphs that are being
+ * shipped over the wire from Gremlin Server. Edge list format is a bit easier for non-JVM languages to work
+ * with as a format and doesn't require a cache for loading (as vertex labels are not serialized in adjacency
+ * list).
+ */
+ final static class TinkerGraphJacksonSerializer extends StdSerializer<TinkerGraph> {
+
+ public TinkerGraphJacksonSerializer() {
+ super(TinkerGraph.class);
+ }
+
+ @Override
+ public void serialize(final TinkerGraph graph, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
+ throws IOException {
+ ser(graph, jsonGenerator, serializerProvider, null);
+ }
+
+ @Override
+ public void serializeWithType(final TinkerGraph graph, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
+ ser(graph, jsonGenerator, serializerProvider, typeSerializer);
+ }
+
+ private void ser(final TinkerGraph graph, final JsonGenerator jsonGenerator,
+ final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
+ GraphSONUtil.writeStartObject(graph, jsonGenerator, typeSerializer);
+ jsonGenerator.writeFieldName(GraphSONTokens.VERTICES);
+ GraphSONUtil.writeStartArray(graph, jsonGenerator, typeSerializer);
+
+ final Iterator<Vertex> vertices = graph.vertices();
+ while (vertices.hasNext()) {
+ serializerProvider.defaultSerializeValue(vertices.next(), jsonGenerator);
+ }
+
+ GraphSONUtil.writeEndArray(graph, jsonGenerator, typeSerializer);
+ jsonGenerator.writeFieldName(GraphSONTokens.EDGES);
+ GraphSONUtil.writeStartArray(graph, jsonGenerator, typeSerializer);
+
+ final Iterator<Edge> edges = graph.edges();
+ while (edges.hasNext()) {
+ serializerProvider.defaultSerializeValue(edges.next(), jsonGenerator);
+ }
+
+ GraphSONUtil.writeEndArray(graph, jsonGenerator, typeSerializer);
+ GraphSONUtil.writeEndObject(graph, jsonGenerator, typeSerializer);
+ }
+ }
+
+ /**
+ * Deserializes the edge list format.
+ */
+ static class TinkerGraphJacksonDeserializer extends StdDeserializer<TinkerGraph> {
+ public TinkerGraphJacksonDeserializer() {
+ super(TinkerGraph.class);
+ }
+
+ @Override
+ public TinkerGraph deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
+ final TinkerGraph graph = TinkerGraph.open();
+
+ final List<Map<String, Object>> edges;
+ final List<Map<String, Object>> vertices;
+ if (!jsonParser.getCurrentToken().isStructStart()) {
+ if (!jsonParser.getCurrentName().equals(GraphSONTokens.VERTICES))
+ throw new IOException(String.format("Expected a '%s' key", GraphSONTokens.VERTICES));
+
+ jsonParser.nextToken();
+
+ vertices = deserializationContext.readValue(jsonParser, List.class);
+ jsonParser.nextToken();
+
+ if (!jsonParser.getCurrentName().equals(GraphSONTokens.EDGES))
+ throw new IOException(String.format("Expected a '%s' key", GraphSONTokens.EDGES));
+
+ jsonParser.nextToken();
+ edges = (List<Map<String, Object>>) deserializationContext.readValue(jsonParser, List.class);
+
+ } else {
+ final Map<String, Object> graphData = deserializationContext.readValue(jsonParser, Map.class);
+ vertices = (List<Map<String,Object>>) graphData.get(GraphSONTokens.VERTICES);
+ edges = (List<Map<String,Object>>) graphData.get(GraphSONTokens.EDGES);
+ }
+
+ for (Map<String, Object> vertexData : vertices) {
+ final DetachedVertex detached = new DetachedVertex(vertexData.get(GraphSONTokens.ID),
+ vertexData.get(GraphSONTokens.LABEL).toString(), (Map<String,Object>) vertexData.get(GraphSONTokens.PROPERTIES));
+ detached.attach(Attachable.Method.getOrCreate(graph));
+ }
+
+ for (Map<String, Object> edgeData : edges) {
+ final DetachedEdge detached = new DetachedEdge(edgeData.get(GraphSONTokens.ID),
+ edgeData.get(GraphSONTokens.LABEL).toString(), (Map<String,Object>) edgeData.get(GraphSONTokens.PROPERTIES),
+ Pair.with(edgeData.get(GraphSONTokens.OUT), edgeData.get(GraphSONTokens.OUT_LABEL).toString()),
+ Pair.with(edgeData.get(GraphSONTokens.IN), edgeData.get(GraphSONTokens.IN_LABEL).toString()));
+ detached.attach(Attachable.Method.getOrCreate(graph));
+ }
+
+ return graph;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b44ec666/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/IoDataGenerationTest.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/IoDataGenerationTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/IoDataGenerationTest.java
index 86fc733..b4356b6 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/IoDataGenerationTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/IoDataGenerationTest.java
@@ -23,33 +23,31 @@ import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.TestHelper;
import org.apache.tinkerpop.gremlin.algorithm.generator.DistributionGenerator;
import org.apache.tinkerpop.gremlin.algorithm.generator.PowerLawDistribution;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.*;
import org.apache.tinkerpop.gremlin.structure.io.GraphReader;
import org.apache.tinkerpop.gremlin.structure.io.graphml.GraphMLWriter;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONReader;
+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.gryo.GryoReader;
import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoWriter;
import org.junit.BeforeClass;
import org.junit.Test;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
+import java.util.Iterator;
import java.util.stream.IntStream;
+import static org.junit.Assert.assertEquals;
+
/**
* Less of a test of functionality and more of a tool to help generate data files for TinkerPop.
*
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public class IoDataGenerationTest {
- private static String tempPath;
+ private static final String tempPath;
static {
tempPath = TestHelper.makeTestDataPath(TinkerGraphTest.class, "tinkerpop-io").getPath() + File.separator;
@@ -173,6 +171,23 @@ public class IoDataGenerationTest {
os.close();
}
+ @Test
+ public void shouldWriteAndReadClassicGraphAsGraphSONV2d0WithTypes() throws IOException {
+ Graph g = TinkerFactory.createClassic();
+ final OutputStream os = new FileOutputStream(tempPath + "tinkerpop-classic-V2d0-typed.json");
+ GraphSONWriter.build().mapper(GraphSONMapper.build().version(GraphSONVersion.V2_0).typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES).create())
+ .create().writeGraph(os, g);
+ os.close();
+
+ Graph readG = TinkerGraph.open();
+ final InputStream is = new FileInputStream(tempPath + "tinkerpop-classic-V2d0-typed.json");
+ GraphSONReader.build().mapper(GraphSONMapper.build().version(GraphSONVersion.V2_0).typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES).create()).create().readGraph(is, readG);
+ is.close();
+
+ assertEquals(approximateGraphsCheck(g, readG), true);
+ }
+
+
/**
* No assertions. Just write out the graph for convenience.
*/
@@ -275,4 +290,78 @@ public class IoDataGenerationTest {
GraphSONWriter.build().mapper(GraphSONMapper.build().embedTypes(true).create()).create().writeGraph(os4, g);
os4.close();
}
+
+ @Test
+ public void shouldWriteGratefulDeadGraphSONV2d0() throws IOException {
+ final TinkerGraph g = TinkerGraph.open();
+ final TinkerGraph readG = TinkerGraph.open();
+
+ final GraphReader reader = GryoReader.build().create();
+ try (final InputStream stream = AbstractGremlinTest.class.getResourceAsStream("/org/apache/tinkerpop/gremlin/structure/io/gryo/grateful-dead.kryo")) {
+ reader.readGraph(stream, g);
+ }
+ final OutputStream os2 = new FileOutputStream(tempPath + "grateful-dead-V2d0-typed.json");
+ GraphSONWriter.build().mapper(GraphSONMapper.build().version(GraphSONVersion.V2_0).typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES).create()).create().writeGraph(os2, g);
+ os2.close();
+
+ final InputStream is = new FileInputStream(tempPath + "grateful-dead-V2d0-typed.json");
+ GraphSONReader.build().mapper(GraphSONMapper.build().version(GraphSONVersion.V2_0).typeInfo(GraphSONMapper.TypeInfo.PARTIAL_TYPES).create()).create().readGraph(is, readG);
+ is.close();
+
+ assertEquals(approximateGraphsCheck(g, readG), true);
+ }
+
+ /**
+ * Checks sequentially vertices and egdes of both graphs. Will check sequentially Vertex IDs, Vertex Properties IDs
+ * and values and classes. Then same for edges. To use when serializing a Graph and deserializing the supposedly
+ * same Graph.
+ */
+ private boolean approximateGraphsCheck(Graph g1, Graph g2) {
+ Iterator<Vertex> itV = g1.vertices();
+ Iterator<Vertex> itVRead = g2.vertices();
+
+ while (itV.hasNext()) {
+ Vertex v = itV.next();
+ Vertex vRead = itVRead.next();
+ // Will only check IDs but that's 'good' enough.
+ if (!v.equals(vRead)) {
+ return false;
+ }
+
+ Iterator itVP = v.properties();
+ Iterator itVPRead = vRead.properties();
+ while (itVP.hasNext()) {
+ VertexProperty vp = (VertexProperty) itVP.next();
+ VertexProperty vpRead = (VertexProperty) itVPRead.next();
+ if (!vp.value().equals(vpRead.value())) {
+ return false;
+ }
+ }
+ }
+
+
+ Iterator<Edge> itE = g1.edges();
+ Iterator<Edge> itERead = g2.edges();
+
+ while (itE.hasNext()) {
+ Edge e = itE.next();
+ Edge eRead = itERead.next();
+ // Will only check IDs but that's good enough.
+ if (!e.equals(eRead)) {
+ return false;
+ }
+
+ Iterator itEP = e.properties();
+ Iterator itEPRead = eRead.properties();
+ while (itEP.hasNext()) {
+ Property ep = (Property) itEP.next();
+ Property epRead = (Property) itEPRead.next();
+ if (!ep.value().equals(epRead.value())
+ || !ep.equals(epRead)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
}