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/02/13 13:31:06 UTC

[19/37] incubator-tinkerpop git commit: Improved GraphSON support of java.time.* packages.

Improved GraphSON support of java.time.* packages.

Serialized all classes currently serialized by Gryo using ISO-8061 format.  Using the embedded type option actually allow serialization back to java.time.* classes rather than coercing them to other types.


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

Branch: refs/heads/master
Commit: cee96fdb29fe354837845da961c0f6252e007b5a
Parents: e157514
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Feb 12 08:11:42 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Feb 12 08:11:42 2016 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   2 +
 .../structure/io/graphson/GraphSONModule.java   |  47 ++-
 .../io/graphson/GraphSONSerializers.java        |  50 +--
 .../io/graphson/JavaTimeSerializers.java        | 326 +++++++++++++++++++
 .../io/graphson/JavaUtilSerializers.java        |  86 +++++
 .../GraphSONMapperEmbeddedTypeTest.java         | 134 ++++++++
 .../io/graphson/GraphSONMapperTest.java         | 133 ++++++++
 .../structure/io/gryo/GryoMapperTest.java       |   1 -
 .../handler/HttpGremlinEndpointHandler.java     |  18 +-
 .../server/GremlinServerHttpIntegrateTest.java  |  23 +-
 10 files changed, 764 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index caccb0f..106639e 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,8 @@ image::https://raw.githubusercontent.com/apache/incubator-tinkerpop/master/docs/
 TinkerPop 3.1.2 (NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Added GraphSON serializers for the `java.time.*` classes.
+* Improved the logging of the Gremlin Server REST endpoint as it pertained to script execution failures.
 * `TraversalExplanation` is now `Serializable` and registered with `GryoMapper`.
 * Deprecated `ScriptElementFactory` and made the local `StarGraph` globally available for `ScriptInputFormat`'s `parse()` method.
 * Optimized memory-usage in `TraversalVertexProgram`.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index dba774e..ba9d9ac 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -27,6 +27,19 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.star.StarGraphGraphSONSerializer;
 import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
 import java.util.Map;
 
 /**
@@ -55,6 +68,7 @@ abstract class GraphSONModule extends SimpleModule {
          */
         protected GraphSONModuleV1d0(final boolean normalize) {
             super("graphson-1.0");
+            // graph
             addSerializer(Edge.class, new GraphSONSerializers.EdgeJacksonSerializer(normalize));
             addSerializer(Vertex.class, new GraphSONSerializers.VertexJacksonSerializer(normalize));
             addSerializer(VertexProperty.class, new GraphSONSerializers.VertexPropertyJacksonSerializer(normalize));
@@ -62,7 +76,38 @@ abstract class GraphSONModule extends SimpleModule {
             addSerializer(TraversalMetrics.class, new GraphSONSerializers.TraversalMetricsJacksonSerializer());
             addSerializer(Path.class, new GraphSONSerializers.PathJacksonSerializer());
             addSerializer(StarGraphGraphSONSerializer.DirectionalStarGraph.class, new StarGraphGraphSONSerializer(normalize));
-            addSerializer(Map.Entry.class, new GraphSONSerializers.MapEntryJacksonSerializer());
+
+            // java.util
+            addSerializer(Map.Entry.class, new JavaUtilSerializers.MapEntryJacksonSerializer());
+
+            // java.time
+            addSerializer(Duration.class, new JavaTimeSerializers.DurationJacksonSerializer());
+            addSerializer(Instant.class, new JavaTimeSerializers.InstantJacksonSerializer());
+            addSerializer(LocalDate.class, new JavaTimeSerializers.LocalDateJacksonSerializer());
+            addSerializer(LocalDateTime.class, new JavaTimeSerializers.LocalDateTimeJacksonSerializer());
+            addSerializer(LocalTime.class, new JavaTimeSerializers.LocalTimeJacksonSerializer());
+            addSerializer(MonthDay.class, new JavaTimeSerializers.MonthDayJacksonSerializer());
+            addSerializer(OffsetDateTime.class, new JavaTimeSerializers.OffsetDateTimeJacksonSerializer());
+            addSerializer(OffsetTime.class, new JavaTimeSerializers.OffsetTimeJacksonSerializer());
+            addSerializer(Period.class, new JavaTimeSerializers.PeriodJacksonSerializer());
+            addSerializer(Year.class, new JavaTimeSerializers.YearJacksonSerializer());
+            addSerializer(YearMonth.class, new JavaTimeSerializers.YearMonthJacksonSerializer());
+            addSerializer(ZonedDateTime.class, new JavaTimeSerializers.ZonedDateTimeJacksonSerializer());
+            addSerializer(ZoneOffset.class, new JavaTimeSerializers.ZoneOffsetJacksonSerializer());
+
+            addDeserializer(Duration.class, new JavaTimeSerializers.DurationJacksonDeserializer());
+            addDeserializer(Instant.class, new JavaTimeSerializers.InstantJacksonDeserializer());
+            addDeserializer(LocalDate.class, new JavaTimeSerializers.LocalDateJacksonDeserializer());
+            addDeserializer(LocalDateTime.class, new JavaTimeSerializers.LocalDateTimeJacksonDeserializer());
+            addDeserializer(LocalTime.class, new JavaTimeSerializers.LocalTimeJacksonDeserializer());
+            addDeserializer(MonthDay.class, new JavaTimeSerializers.MonthDayJacksonDeserializer());
+            addDeserializer(OffsetDateTime.class, new JavaTimeSerializers.OffsetDateTimeJacksonDeserializer());
+            addDeserializer(OffsetTime.class, new JavaTimeSerializers.OffsetTimeJacksonDeserializer());
+            addDeserializer(Period.class, new JavaTimeSerializers.PeriodJacksonDeserializer());
+            addDeserializer(Year.class, new JavaTimeSerializers.YearJacksonDeserializer());
+            addDeserializer(YearMonth.class, new JavaTimeSerializers.YearMonthJacksonDeserializer());
+            addDeserializer(ZonedDateTime.class, new JavaTimeSerializers.ZonedDateTimeJacksonDeserializer());
+            addDeserializer(ZoneOffset.class, new JavaTimeSerializers.ZoneOffsetJacksonDeserializer());
         }
 
         public static Builder build() {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
index 010ca74..5b2a8b7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializers.java
@@ -32,7 +32,6 @@ 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.core.JsonProcessingException;
-import org.apache.tinkerpop.shaded.jackson.databind.SerializationFeature;
 import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
 import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
 import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdKeySerializer;
@@ -41,7 +40,6 @@ import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -49,7 +47,7 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 /**
- * Class used to serialize graph-based objects such as vertices, edges, properties, and paths. These serializers
+ * GraphSON serializers for graph-based objects such as vertices, edges, properties, and paths. These serializers
  * present a generalized way to serialize the implementations of core interfaces.
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -328,52 +326,6 @@ final class GraphSONSerializers {
         }
     }
 
-    final static class MapEntryJacksonSerializer extends StdSerializer<Map.Entry> {
-
-        public MapEntryJacksonSerializer() {
-            super(Map.Entry.class);
-        }
-
-        @Override
-        public void serialize(final Map.Entry entry, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
-                throws IOException {
-            ser(entry, jsonGenerator, serializerProvider, null);
-        }
-        @Override
-        public void serializeWithType(final Map.Entry entry, final JsonGenerator jsonGenerator,
-                                      final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
-            ser(entry, jsonGenerator, serializerProvider, typeSerializer);
-        }
-
-        private static void ser(final Map.Entry entry, final JsonGenerator jsonGenerator,
-                                final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
-            jsonGenerator.writeStartObject();
-            if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
-
-            // this treatment of keys is consistent with the current GraphSONKeySerializer which extends the
-            // StdKeySerializer
-            final Object key = entry.getKey();
-            final Class cls = key.getClass();
-            String k;
-            if (cls == String.class)
-                k = (String) key;
-            else if (Element.class.isAssignableFrom(cls))
-                k = ((Element) key).id().toString();
-            else if(Date.class.isAssignableFrom(cls)) {
-                if (serializerProvider.isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS))
-                    k = String.valueOf(((Date) key).getTime());
-                else
-                    k = serializerProvider.getConfig().getDateFormat().format((Date) key);
-            } else if(cls == Class.class)
-                k = ((Class) key).getName();
-            else
-                k = key.toString();
-
-            serializerProvider.defaultSerializeField(k, entry.getValue(), jsonGenerator);
-            jsonGenerator.writeEndObject();
-        }
-    }
-
     private static void serializerVertexProperty(final VertexProperty property, final JsonGenerator jsonGenerator,
                                                  final SerializerProvider serializerProvider,
                                                  final TypeSerializer typeSerializer, final boolean normalize,

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaTimeSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaTimeSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaTimeSerializers.java
new file mode 100644
index 0000000..7ceae94
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaTimeSerializers.java
@@ -0,0 +1,326 @@
+/*
+ * 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.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
+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 java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+/**
+ * GraphSON serializers for classes in {@code java.time.*}.
+ */
+final class JavaTimeSerializers {
+
+    private JavaTimeSerializers() {}
+
+    /**
+     * Base class for serializing the {@code java.time.*} to ISO-8061 formats.
+     */
+    static abstract class AbstractJavaTimeSerializer<T> extends StdSerializer<T> {
+
+        public AbstractJavaTimeSerializer(final Class<T> clazz) {
+            super(clazz);
+        }
+
+        @Override
+        public void serialize(final T value, final JsonGenerator gen,
+                              final SerializerProvider serializerProvider) throws IOException {
+            gen.writeString(value.toString());
+        }
+
+        @Override
+        public void serializeWithType(final T value, final JsonGenerator gen,
+                                      final SerializerProvider serializers, final TypeSerializer typeSer) throws IOException {
+            typeSer.writeTypePrefixForObject(value, gen);
+            gen.writeStringField(GraphSONTokens.VALUE, value.toString());
+            typeSer.writeTypeSuffixForObject(value, gen);
+        }
+    }
+    /**
+     * Base class for serializing the {@code java.time.*} from ISO-8061 formats.
+     */
+    abstract static class AbstractJavaTimeJacksonDeserializer<T> extends StdDeserializer<T> {
+        public AbstractJavaTimeJacksonDeserializer(final Class<T> clazz) {
+            super(clazz);
+        }
+
+        public abstract T parse(final String val);
+
+        @Override
+        public T deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
+            if (!jsonParser.getText().equals(GraphSONTokens.VALUE))
+                throw new IOException(String.format("Invalid format for %s - expecting '%s' with a text value in ISO-8061 format", _valueClass.getSimpleName(), GraphSONTokens.VALUE));
+
+            return parse(jsonParser.nextTextValue());
+        }
+    }
+
+    final static class DurationJacksonSerializer extends AbstractJavaTimeSerializer<Duration> {
+
+        public DurationJacksonSerializer() {
+            super(Duration.class);
+        }
+    }
+
+    final static class DurationJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<Duration> {
+        public DurationJacksonDeserializer() {
+            super(Duration.class);
+        }
+
+        @Override
+        public Duration parse(final String val) {
+            return Duration.parse(val);
+        }
+    }
+
+    final static class InstantJacksonSerializer extends AbstractJavaTimeSerializer<Instant> {
+
+        public InstantJacksonSerializer() {
+            super(Instant.class);
+        }
+    }
+
+    final static class InstantJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<Instant> {
+        public InstantJacksonDeserializer() {
+            super(Instant.class);
+        }
+
+        @Override
+        public Instant parse(final String val) {
+            return Instant.parse(val);
+        }
+    }
+
+    final static class LocalDateJacksonSerializer extends AbstractJavaTimeSerializer<LocalDate> {
+
+        public LocalDateJacksonSerializer() {
+            super(LocalDate.class);
+        }
+    }
+
+    final static class LocalDateJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<LocalDate> {
+        public LocalDateJacksonDeserializer() {
+            super(LocalDate.class);
+        }
+
+        @Override
+        public LocalDate parse(final String val) {
+            return LocalDate.parse(val);
+        }
+    }
+
+    final static class LocalDateTimeJacksonSerializer extends AbstractJavaTimeSerializer<LocalDateTime> {
+
+        public LocalDateTimeJacksonSerializer() {
+            super(LocalDateTime.class);
+        }
+    }
+
+    final static class LocalDateTimeJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<LocalDateTime> {
+        public LocalDateTimeJacksonDeserializer() {
+            super(LocalDateTime.class);
+        }
+
+        @Override
+        public LocalDateTime parse(final String val) {
+            return LocalDateTime.parse(val);
+        }
+    }
+
+    final static class LocalTimeJacksonSerializer extends AbstractJavaTimeSerializer<LocalTime> {
+
+        public LocalTimeJacksonSerializer() {
+            super(LocalTime.class);
+        }
+    }
+
+    final static class LocalTimeJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<LocalTime> {
+        public LocalTimeJacksonDeserializer() {
+            super(LocalTime.class);
+        }
+
+        @Override
+        public LocalTime parse(final String val) {
+            return LocalTime.parse(val);
+        }
+    }
+
+    final static class MonthDayJacksonSerializer extends AbstractJavaTimeSerializer<MonthDay> {
+
+        public MonthDayJacksonSerializer() {
+            super(MonthDay.class);
+        }
+    }
+
+    final static class MonthDayJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<MonthDay> {
+        public MonthDayJacksonDeserializer() {
+            super(MonthDay.class);
+        }
+
+        @Override
+        public MonthDay parse(final String val) {
+            return MonthDay.parse(val);
+        }
+    }
+
+    final static class OffsetDateTimeJacksonSerializer extends AbstractJavaTimeSerializer<OffsetDateTime> {
+
+        public OffsetDateTimeJacksonSerializer() {
+            super(OffsetDateTime.class);
+        }
+    }
+
+    final static class OffsetDateTimeJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<OffsetDateTime> {
+        public OffsetDateTimeJacksonDeserializer() {
+            super(OffsetDateTime.class);
+        }
+
+        @Override
+        public OffsetDateTime parse(final String val) {
+            return OffsetDateTime.parse(val);
+        }
+    }
+
+    final static class OffsetTimeJacksonSerializer extends AbstractJavaTimeSerializer<OffsetTime> {
+
+        public OffsetTimeJacksonSerializer() {
+            super(OffsetTime.class);
+        }
+    }
+
+    final static class OffsetTimeJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<OffsetTime> {
+        public OffsetTimeJacksonDeserializer() {
+            super(OffsetTime.class);
+        }
+
+        @Override
+        public OffsetTime parse(final String val) {
+            return OffsetTime.parse(val);
+        }
+    }
+
+    final static class PeriodJacksonSerializer extends AbstractJavaTimeSerializer<Period> {
+
+        public PeriodJacksonSerializer() {
+            super(Period.class);
+        }
+    }
+
+    final static class PeriodJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<Period> {
+        public PeriodJacksonDeserializer() {
+            super(Period.class);
+        }
+
+        @Override
+        public Period parse(final String val) {
+            return Period.parse(val);
+        }
+    }
+
+    final static class YearJacksonSerializer extends AbstractJavaTimeSerializer<Year> {
+
+        public YearJacksonSerializer() {
+            super(Year.class);
+        }
+    }
+
+    final static class YearJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<Year> {
+        public YearJacksonDeserializer() {
+            super(Year.class);
+        }
+
+        @Override
+        public Year parse(final String val) {
+            return Year.parse(val);
+        }
+    }
+
+    final static class YearMonthJacksonSerializer extends AbstractJavaTimeSerializer<YearMonth> {
+
+        public YearMonthJacksonSerializer() {
+            super(YearMonth.class);
+        }
+    }
+
+    final static class YearMonthJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<YearMonth> {
+        public YearMonthJacksonDeserializer() {
+            super(YearMonth.class);
+        }
+
+        @Override
+        public YearMonth parse(final String val) {
+            return YearMonth.parse(val);
+        }
+    }
+
+    final static class ZonedDateTimeJacksonSerializer extends AbstractJavaTimeSerializer<ZonedDateTime> {
+
+        public ZonedDateTimeJacksonSerializer() {
+            super(ZonedDateTime.class);
+        }
+    }
+
+    final static class ZonedDateTimeJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<ZonedDateTime> {
+        public ZonedDateTimeJacksonDeserializer() {
+            super(ZonedDateTime.class);
+        }
+
+        @Override
+        public ZonedDateTime parse(final String val) {
+            return ZonedDateTime.parse(val);
+        }
+    }
+
+    final static class ZoneOffsetJacksonSerializer extends AbstractJavaTimeSerializer<ZoneOffset> {
+
+        public ZoneOffsetJacksonSerializer() {
+            super(ZoneOffset.class);
+        }
+    }
+
+    final static class ZoneOffsetJacksonDeserializer extends AbstractJavaTimeJacksonDeserializer<ZoneOffset> {
+        public ZoneOffsetJacksonDeserializer() {
+            super(ZoneOffset.class);
+        }
+
+        @Override
+        public ZoneOffset parse(final String val) {
+            return ZoneOffset.of(val);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaUtilSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaUtilSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaUtilSerializers.java
new file mode 100644
index 0000000..4f2f5da
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/JavaUtilSerializers.java
@@ -0,0 +1,86 @@
+/*
+ * 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.structure.Element;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializationFeature;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * GraphSON serializers for classes in {@code java.util.*}.
+ */
+final class JavaUtilSerializers {
+
+    private JavaUtilSerializers() {}
+
+    final static class MapEntryJacksonSerializer extends StdSerializer<Map.Entry> {
+
+        public MapEntryJacksonSerializer() {
+            super(Map.Entry.class);
+        }
+
+        @Override
+        public void serialize(final Map.Entry entry, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
+                throws IOException {
+            ser(entry, jsonGenerator, serializerProvider, null);
+        }
+
+        @Override
+        public void serializeWithType(final Map.Entry entry, final JsonGenerator jsonGenerator,
+                                      final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
+            ser(entry, jsonGenerator, serializerProvider, typeSerializer);
+        }
+
+        private static void ser(final Map.Entry entry, final JsonGenerator jsonGenerator,
+                                final SerializerProvider serializerProvider, final TypeSerializer typeSerializer) throws IOException {
+            jsonGenerator.writeStartObject();
+            if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
+
+            // this treatment of keys is consistent with the current GraphSONKeySerializer which extends the
+            // StdKeySerializer
+            final Object key = entry.getKey();
+            final Class cls = key.getClass();
+            String k;
+            if (cls == String.class)
+                k = (String) key;
+            else if (Element.class.isAssignableFrom(cls))
+                k = ((Element) key).id().toString();
+            else if(Date.class.isAssignableFrom(cls)) {
+                if (serializerProvider.isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS))
+                    k = String.valueOf(((Date) key).getTime());
+                else
+                    k = serializerProvider.getConfig().getDateFormat().format((Date) key);
+            } else if(cls == Class.class)
+                k = ((Class) key).getName();
+            else
+                k = key.toString();
+
+            serializerProvider.defaultSerializeField(k, entry.getValue(), jsonGenerator);
+            jsonGenerator.writeEndObject();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..c7549f9
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.kryo.io.Input;
+import org.apache.tinkerpop.shaded.kryo.io.Output;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import static org.junit.Assert.assertEquals;
+
+public class GraphSONMapperEmbeddedTypeTest {
+    private final ObjectMapper mapper = GraphSONMapper.build().embedTypes(true).create().createMapper();
+
+    @Test
+    public void shouldHandleDuration()throws Exception  {
+        final Duration o = Duration.ZERO;
+        assertEquals(o, serializeDeserialize(o, Duration.class));
+    }
+    @Test
+    public void shouldHandleInstant()throws Exception  {
+        final Instant o = Instant.ofEpochMilli(System.currentTimeMillis());
+        assertEquals(o, serializeDeserialize(o, Instant.class));
+    }
+
+    @Test
+    public void shouldHandleLocalDate()throws Exception  {
+        final LocalDate o = LocalDate.now();
+        assertEquals(o, serializeDeserialize(o, LocalDate.class));
+    }
+
+    @Test
+    public void shouldHandleLocalDateTime()throws Exception  {
+        final LocalDateTime o = LocalDateTime.now();
+        assertEquals(o, serializeDeserialize(o, LocalDateTime.class));
+    }
+
+    @Test
+    public void shouldHandleLocalTime()throws Exception  {
+        final LocalTime o = LocalTime.now();
+        assertEquals(o, serializeDeserialize(o, LocalTime.class));
+    }
+
+    @Test
+    public void shouldHandleMonthDay()throws Exception  {
+        final MonthDay o = MonthDay.now();
+        assertEquals(o, serializeDeserialize(o, MonthDay.class));
+    }
+
+    @Test
+    public void shouldHandleOffsetDateTime()throws Exception  {
+        final OffsetDateTime o = OffsetDateTime.now();
+        assertEquals(o, serializeDeserialize(o, OffsetDateTime.class));
+    }
+
+    @Test
+    public void shouldHandleOffsetTime()throws Exception  {
+        final OffsetTime o = OffsetTime.now();
+        assertEquals(o, serializeDeserialize(o, OffsetTime.class));
+    }
+
+    @Test
+    public void shouldHandlePeriod()throws Exception  {
+        final Period o = Period.ofDays(3);
+        assertEquals(o, serializeDeserialize(o, Period.class));
+    }
+
+    @Test
+    public void shouldHandleYear()throws Exception  {
+        final Year o = Year.now();
+        assertEquals(o, serializeDeserialize(o, Year.class));
+    }
+
+    @Test
+    public void shouldHandleYearMonth()throws Exception  {
+        final YearMonth o = YearMonth.now();
+        assertEquals(o, serializeDeserialize(o, YearMonth.class));
+    }
+
+    @Test
+    public void shouldHandleZonedDateTime()throws Exception  {
+        final ZonedDateTime o = ZonedDateTime.now();
+        assertEquals(o, serializeDeserialize(o, ZonedDateTime.class));
+    }
+
+    @Test
+    public void shouldHandleZonedOffset()throws Exception  {
+        final ZoneOffset o  = ZonedDateTime.now().getOffset();
+        assertEquals(o, serializeDeserialize(o, ZoneOffset.class));
+    }
+
+    public <T> T serializeDeserialize(final Object o, final Class<T> clazz) throws Exception {
+        try (final ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+            mapper.writeValue(stream, o);
+
+            try (final InputStream inputStream = new ByteArrayInputStream(stream.toByteArray())) {
+                return mapper.readValue(inputStream, clazz);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..0a16a4e
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.shaded.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import static org.junit.Assert.assertEquals;
+
+public class GraphSONMapperTest {
+    private final ObjectMapper mapper = GraphSONMapper.build().embedTypes(false).create().createMapper();
+
+    @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);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java
index a915797..e92eaf9 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java
@@ -47,7 +47,6 @@ import java.time.OffsetTime;
 import java.time.Period;
 import java.time.Year;
 import java.time.YearMonth;
-import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.ArrayList;

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
index f03f9c2..d37a1bc 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
@@ -253,7 +253,8 @@ public class HttpGremlinEndpointHandler extends ChannelInboundHandlerAdapter {
                         }));
 
                 evalFuture.exceptionally(t -> {
-                    sendError(ctx, INTERNAL_SERVER_ERROR, String.format("Error encountered evaluating script: %s", requestArguments.getValue0()));
+                    sendError(ctx, INTERNAL_SERVER_ERROR,
+                            String.format("Error encountered evaluating script: %s", requestArguments.getValue0()), Optional.of(t));
                     promise.setFailure(t);
                     return null;
                 });
@@ -437,8 +438,19 @@ public class HttpGremlinEndpointHandler extends ChannelInboundHandlerAdapter {
             return node.asText();
     }
 
-    private static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status, final String message) {
-        logger.warn("Invalid request - responding with {} and {}", status, message);
+
+    private static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
+                                  final String message) {
+        sendError(ctx, status, message, Optional.empty());
+    }
+
+    private static void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status,
+                                  final String message, final Optional<Throwable> t) {
+        if (t.isPresent())
+            logger.warn(String.format("Invalid request - responding with %s and %s", status, message), t.get());
+        else
+            logger.warn(String.format("Invalid request - responding with %s and %s", status, message));
+
         errorMeter.mark();
         final ObjectNode node = mapper.createObjectNode();
         node.put("message", message);

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/cee96fdb/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
----------------------------------------------------------------------
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 00e757c..f8efda9 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
@@ -34,8 +34,9 @@ import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.junit.Test;
 
 import java.io.File;
-import java.util.Arrays;
+import java.time.Instant;
 import java.util.Base64;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -64,7 +65,7 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra
             case "should200OnPOSTWithGremlinJsonEndcodedBodyWithIteratorResult":
             case "should200OnPOSTWithGremlinJsonEndcodedBodyWithIteratorResultAndAliases":
             case "should200OnGETWithGremlinQueryStringArgumentWithIteratorResultAndAliases":
-                settings.scriptEngines.get("gremlin-groovy").scripts = Arrays.asList("scripts/generate-classic.groovy");
+                settings.scriptEngines.get("gremlin-groovy").scripts = Collections.singletonList("scripts/generate-classic.groovy");
                 break;
             case "should200OnPOSTTransactionalGraph":
                 deleteDirectory(new File("/tmp/neo4j"));
@@ -428,6 +429,24 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra
     }
 
     @Test
+    public void should200OnPOSTWithGremlinJsonEndcodedBodyForJavaTime() throws Exception {
+        // basic test of java.time.* serialization over JSON from the server perspective. more complete tests
+        // exist in gremlin-core
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpPost httppost = new HttpPost("http://localhost:8182");
+        httppost.addHeader("Content-Type", "application/json");
+        httppost.setEntity(new StringEntity("{\"gremlin\":\"java.time.Instant.MAX\"}", Consts.UTF_8));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httppost)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals("application/json", response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(Instant.MAX, Instant.parse(node.get("result").get("data").get(0).asText()));
+        }
+    }
+
+    @Test
     public void should200OnPOSTTransactionalGraph() throws Exception {
         assumeNeo4jIsPresent();