Merge branch 'tp32' into tp33

Conflicts:
        
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractGraphSONTypeSerializer.java
        
gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java


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

Branch: refs/heads/tp33
Commit: a3624f7e2f23d290ac2ad475f88716f98eeb8b7c
Parents: dd3a54e 7bff988
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Mar 8 08:08:40 2018 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Mar 8 08:08:40 2018 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../AbstractGraphSONTypeSerializer.java         | 80 +-------------------
 .../io/graphson/GraphSONTypeSerializerV2d0.java | 38 ++++++++++
 .../io/graphson/GraphSONTypeSerializerV3d0.java | 72 +++++++++++-------
 .../GraphSONMapperPartialEmbeddedTypeTest.java  | 33 ++++++++
 gremlin-shaded/pom.xml                          |  2 +-
 6 files changed, 120 insertions(+), 106 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/CHANGELOG.asciidoc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractGraphSONTypeSerializer.java
----------------------------------------------------------------------
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractGraphSONTypeSerializer.java
index 6eb65e1,0000000..fa90b2c
mode 100644,000000..100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractGraphSONTypeSerializer.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/AbstractGraphSONTypeSerializer.java
@@@ -1,173 -1,0 +1,99 @@@
 +/*
 + * 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.annotation.JsonTypeInfo;
 +import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
++import org.apache.tinkerpop.shaded.jackson.core.JsonToken;
++import org.apache.tinkerpop.shaded.jackson.core.type.WritableTypeId;
 +import org.apache.tinkerpop.shaded.jackson.databind.BeanProperty;
 +import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeIdResolver;
 +import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
 +
 +import java.io.IOException;
 +import java.util.HashMap;
 +import java.util.Map;
 +
 +/**
 + * Extension of the Jackson's default TypeSerializer. An instance of this 
object will be passed to the serializers
 + * on which they can safely call the utility methods to serialize types and 
making it compatible with the version
 + * 2.0+ of GraphSON.
 + *
 + * @author Kevin Gallardo (https://kgdo.me)
 + * @author Stephen Mallette (http://stephen.genoprime.com)
 + */
 +public abstract class AbstractGraphSONTypeSerializer extends TypeSerializer {
 +
 +    protected final TypeIdResolver idRes;
 +    protected final String propertyName;
 +    protected final TypeInfo typeInfo;
 +    protected final String valuePropertyName;
 +    protected final Map<Class, Class> classMap = new HashMap<>();
 +
 +    AbstractGraphSONTypeSerializer(final TypeIdResolver idRes, final String 
propertyName, final TypeInfo typeInfo,
 +                                   final String valuePropertyName) {
 +        this.idRes = idRes;
 +        this.propertyName = propertyName;
 +        this.typeInfo = typeInfo;
 +        this.valuePropertyName = valuePropertyName;
 +    }
 +
 +
 +    @Override
 +    public TypeSerializer forProperty(final BeanProperty beanProperty) {
 +        return this;
 +    }
 +
 +    @Override
 +    public JsonTypeInfo.As getTypeInclusion() {
-         return null;
++        return JsonTypeInfo.As.WRAPPER_OBJECT;
 +    }
 +
 +    @Override
 +    public String getPropertyName() {
 +        return propertyName;
 +    }
 +
 +    @Override
 +    public TypeIdResolver getTypeIdResolver() {
 +        return idRes;
 +    }
 +
-     @Override
-     public void writeTypePrefixForScalar(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (canWriteTypeId()) {
-             writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(o, getClassFromObject(o)));
-         }
-     }
- 
-     @Override
-     public void writeTypePrefixForObject(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         jsonGenerator.writeStartObject();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypePrefix(Map);
-     }
- 
-     @Override
-     public void writeTypePrefixForArray(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         jsonGenerator.writeStartArray();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypePrefix(List);
-     }
- 
-     @Override
-     public void writeTypeSuffixForScalar(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (canWriteTypeId()) {
-             writeTypeSuffix(jsonGenerator);
-         }
-     }
- 
-     @Override
-     public void writeTypeSuffixForObject(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         jsonGenerator.writeEndObject();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypeSuffix(Map);
-     }
- 
-     @Override
-     public void writeTypeSuffixForArray(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         jsonGenerator.writeEndArray();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypeSuffix(List);
-     }
- 
-     @Override
-     public void writeCustomTypePrefixForScalar(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         if (canWriteTypeId()) {
-             writeTypePrefix(jsonGenerator, s);
-         }
-     }
- 
-     @Override
-     public void writeCustomTypePrefixForObject(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         jsonGenerator.writeStartObject();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypePrefix(s);
-     }
- 
-     @Override
-     public void writeCustomTypePrefixForArray(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         jsonGenerator.writeStartArray();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypePrefix(s);
-     }
- 
-     @Override
-     public void writeCustomTypeSuffixForScalar(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         if (canWriteTypeId()) {
-             writeTypeSuffix(jsonGenerator);
-         }
-     }
- 
-     @Override
-     public void writeCustomTypeSuffixForObject(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         jsonGenerator.writeEndObject();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypeSuffix(s);
-     }
- 
-     @Override
-     public void writeCustomTypeSuffixForArray(final Object o, final 
JsonGenerator jsonGenerator, final String s) throws IOException {
-         jsonGenerator.writeEndArray();
-         // TODO: FULL_TYPES should be implemented here as : if 
(fullTypesModeEnabled()) writeTypeSuffix(s);
-     }
- 
 +    protected boolean canWriteTypeId() {
 +        return typeInfo != null
 +                && typeInfo == TypeInfo.PARTIAL_TYPES;
 +    }
 +
 +    protected void writeTypePrefix(final JsonGenerator jsonGenerator, final 
String s) throws IOException {
 +        jsonGenerator.writeStartObject();
 +        jsonGenerator.writeStringField(this.getPropertyName(), s);
 +        jsonGenerator.writeFieldName(this.valuePropertyName);
 +    }
 +
 +    protected void writeTypeSuffix(final JsonGenerator jsonGenerator) throws 
IOException {
 +        jsonGenerator.writeEndObject();
 +    }
 +
 +    /**
 +     * We force only **one** translation of a Java object to a domain 
specific object. i.e. users register typeIDs
 +     * and serializers/deserializers for the predefined types we have in the 
spec. Graph, Vertex, Edge,
 +     * VertexProperty, etc... And **not** their implementations (TinkerGraph, 
DetachedVertex, TinkerEdge, etc..)
 +     */
 +    protected abstract Class getClassFromObject(final Object o);
 +}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
----------------------------------------------------------------------
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
index 993f110,0000000..f0d437f
mode 100644,000000..100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
@@@ -1,112 -1,0 +1,150 @@@
 +/*
 + * 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.Operator;
 +import org.apache.tinkerpop.gremlin.process.traversal.Order;
 +import org.apache.tinkerpop.gremlin.process.traversal.Path;
 +import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 +import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 +import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 +import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 +import 
org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 +import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
 +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
 +import org.apache.tinkerpop.gremlin.structure.Column;
 +import org.apache.tinkerpop.gremlin.structure.Direction;
 +import org.apache.tinkerpop.gremlin.structure.Edge;
 +import org.apache.tinkerpop.gremlin.structure.Property;
 +import org.apache.tinkerpop.gremlin.structure.T;
 +import org.apache.tinkerpop.gremlin.structure.Vertex;
 +import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 +import org.apache.tinkerpop.gremlin.util.function.Lambda;
++import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
++import org.apache.tinkerpop.shaded.jackson.core.JsonToken;
++import org.apache.tinkerpop.shaded.jackson.core.type.WritableTypeId;
 +import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeIdResolver;
 +
++import java.io.IOException;
 +import java.net.InetAddress;
 +import java.nio.ByteBuffer;
 +
 +/**
 + * GraphSON 2.0 {@code TypeSerializer}.
 + *
 + * @author Kevin Gallardo (https://kgdo.me)
 + * @author Stephen Mallette (http://stephen.genoprime.com)
 + */
 +public class GraphSONTypeSerializerV2d0 extends 
AbstractGraphSONTypeSerializer {
 +
 +    GraphSONTypeSerializerV2d0(final TypeIdResolver idRes, final String 
propertyName, final TypeInfo typeInfo,
 +                               final String valuePropertyName) {
 +        super(idRes, propertyName, typeInfo, valuePropertyName);
 +    }
 +
 +    @Override
++    public WritableTypeId writeTypePrefix(final JsonGenerator jsonGenerator, 
final WritableTypeId writableTypeId) throws IOException {
++        if (writableTypeId.valueShape == JsonToken.VALUE_STRING) {
++            if (canWriteTypeId()) {
++                writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(writableTypeId.forValue, 
getClassFromObject(writableTypeId.forValue)));
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_OBJECT) {
++            jsonGenerator.writeStartObject();
++        } else if (writableTypeId.valueShape == JsonToken.START_ARRAY) {
++            jsonGenerator.writeStartArray();
++        } else {
++            throw new IllegalStateException("Could not write prefix");
++        }
++
++        return writableTypeId;
++    }
++
++    @Override
++    public WritableTypeId writeTypeSuffix(final JsonGenerator jsonGenerator, 
final WritableTypeId writableTypeId) throws IOException {
++        if (writableTypeId.valueShape == JsonToken.VALUE_STRING) {
++            if (canWriteTypeId()) {
++                writeTypeSuffix(jsonGenerator);
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_OBJECT) {
++            jsonGenerator.writeEndObject();
++        } else if (writableTypeId.valueShape == JsonToken.START_ARRAY) {
++            jsonGenerator.writeEndArray();
++        } else {
++            throw new IllegalStateException("Could not write suffix");
++        }
++
++        return writableTypeId;
++    }
++
++    @Override
 +    protected Class getClassFromObject(final Object o) {
 +        final Class c = o.getClass();
 +        if (classMap.containsKey(c))
 +            return classMap.get(c);
 +
 +        final Class mapped;
 +        if (Vertex.class.isAssignableFrom(c))
 +            mapped = Vertex.class;
 +        else if (Edge.class.isAssignableFrom(c))
 +            mapped = Edge.class;
 +        else if (Path.class.isAssignableFrom(c))
 +            mapped = Path.class;
 +        else if (VertexProperty.class.isAssignableFrom(c))
 +            mapped = VertexProperty.class;
 +        else if (Metrics.class.isAssignableFrom(c))
 +            mapped = Metrics.class;
 +        else if (TraversalMetrics.class.isAssignableFrom(c))
 +            mapped = TraversalMetrics.class;
 +        else if (Property.class.isAssignableFrom(c))
 +            mapped = Property.class;
 +        else if (ByteBuffer.class.isAssignableFrom(c))
 +            mapped = ByteBuffer.class;
 +        else if (InetAddress.class.isAssignableFrom(c))
 +            mapped = InetAddress.class;
 +        else if (Traverser.class.isAssignableFrom(c))
 +            mapped = Traverser.class;
 +        else if (Lambda.class.isAssignableFrom(c))
 +            mapped = Lambda.class;
 +        else if (VertexProperty.Cardinality.class.isAssignableFrom(c))
 +            mapped = VertexProperty.Cardinality.class;
 +        else if (Column.class.isAssignableFrom(c))
 +            mapped = Column.class;
 +        else if (Direction.class.isAssignableFrom(c))
 +            mapped = Direction.class;
 +        else if (Operator.class.isAssignableFrom(c))
 +            mapped = Operator.class;
 +        else if (Order.class.isAssignableFrom(c))
 +            mapped = Order.class;
 +        else if (Pop.class.isAssignableFrom(c))
 +            mapped = Pop.class;
 +        else if (SackFunctions.Barrier.class.isAssignableFrom(c))
 +            mapped = SackFunctions.Barrier.class;
 +        else if (TraversalOptionParent.Pick.class.isAssignableFrom(c))
 +            mapped = TraversalOptionParent.Pick.class;
 +        else if (Scope.class.isAssignableFrom(c))
 +            mapped = Scope.class;
 +        else if (T.class.isAssignableFrom(c))
 +            mapped = T.class;
 +        else
 +            mapped = c;
 +
 +        classMap.put(c, mapped);
 +        return mapped;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
----------------------------------------------------------------------
diff --cc 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
index 0724e25,0000000..ae1df47
mode 100644,000000..100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
@@@ -1,167 -1,0 +1,183 @@@
 +/*
 + * 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.Operator;
 +import org.apache.tinkerpop.gremlin.process.traversal.Order;
 +import org.apache.tinkerpop.gremlin.process.traversal.Path;
 +import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 +import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 +import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 +import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 +import 
org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 +import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
 +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
 +import org.apache.tinkerpop.gremlin.structure.Column;
 +import org.apache.tinkerpop.gremlin.structure.Direction;
 +import org.apache.tinkerpop.gremlin.structure.Edge;
 +import org.apache.tinkerpop.gremlin.structure.Property;
 +import org.apache.tinkerpop.gremlin.structure.T;
 +import org.apache.tinkerpop.gremlin.structure.Vertex;
 +import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 +import org.apache.tinkerpop.gremlin.util.function.Lambda;
 +import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
++import org.apache.tinkerpop.shaded.jackson.core.JsonToken;
++import org.apache.tinkerpop.shaded.jackson.core.type.WritableTypeId;
 +import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeIdResolver;
 +
 +import java.io.IOException;
 +import java.net.InetAddress;
 +import java.nio.ByteBuffer;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +
 +/**
 + * GraphSON 2.0 {@code TypeSerializer}.
 + *
 + * @author Kevin Gallardo (https://kgdo.me)
 + * @author Stephen Mallette (http://stephen.genoprime.com)
 + */
 +public class GraphSONTypeSerializerV3d0 extends 
AbstractGraphSONTypeSerializer {
 +
 +    GraphSONTypeSerializerV3d0(final TypeIdResolver idRes, final String 
propertyName, final TypeInfo typeInfo,
 +                               final String valuePropertyName) {
 +        super(idRes, propertyName, typeInfo, valuePropertyName);
 +    }
 +
 +    @Override
-     public void writeTypePrefixForObject(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (o instanceof Map) {
-             writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(o, getClassFromObject(o)));
-             jsonGenerator.writeStartArray();
++    public WritableTypeId writeTypePrefix(final JsonGenerator jsonGenerator, 
final WritableTypeId writableTypeId) throws IOException {
++        if (writableTypeId.valueShape == JsonToken.VALUE_STRING) {
++            if (canWriteTypeId()) {
++                writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(writableTypeId.forValue, 
getClassFromObject(writableTypeId.forValue)));
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_OBJECT) {
++            if (writableTypeId.forValue instanceof Map) {
++                writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(writableTypeId.forValue, 
getClassFromObject(writableTypeId.forValue)));
++                jsonGenerator.writeStartArray();
++            } else {
++                jsonGenerator.writeStartObject();
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_ARRAY) {
++            if (writableTypeId.forValue instanceof List || 
writableTypeId.forValue instanceof Set) {
++                writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(writableTypeId.forValue, 
getClassFromObject(writableTypeId.forValue)));
++                jsonGenerator.writeStartArray();
++            } else {
++                jsonGenerator.writeStartArray();
++            }
 +        } else {
-             jsonGenerator.writeStartObject();
++            throw new IllegalStateException("Could not write prefix");
 +        }
-     }
 +
-     @Override
-     public void writeTypeSuffixForObject(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (o instanceof Map) {
-             jsonGenerator.writeEndArray();
-             writeTypeSuffix(jsonGenerator);
-         } else {
-             jsonGenerator.writeEndObject();
-         }
++        return writableTypeId;
 +    }
 +
 +    @Override
-     public void writeTypePrefixForArray(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (o instanceof List || o instanceof Set) {
-             writeTypePrefix(jsonGenerator, 
getTypeIdResolver().idFromValueAndType(o, getClassFromObject(o)));
-             jsonGenerator.writeStartArray();
++    public WritableTypeId writeTypeSuffix(final JsonGenerator jsonGenerator, 
final WritableTypeId writableTypeId) throws IOException {
++        if (writableTypeId.valueShape == JsonToken.VALUE_STRING) {
++            if (canWriteTypeId()) {
++                writeTypeSuffix(jsonGenerator);
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_OBJECT) {
++            if (writableTypeId.forValue instanceof Map) {
++                jsonGenerator.writeEndArray();
++                writeTypeSuffix(jsonGenerator);
++            } else {
++                jsonGenerator.writeEndObject();
++            }
++        } else if (writableTypeId.valueShape == JsonToken.START_ARRAY) {
++            if (writableTypeId.forValue instanceof List || 
writableTypeId.forValue instanceof Set) {
++                jsonGenerator.writeEndArray();
++                writeTypeSuffix(jsonGenerator);
++            } else {
++                jsonGenerator.writeEndArray();
++            }
 +        } else {
-             jsonGenerator.writeStartArray();
++            throw new IllegalStateException("Could not write suffix");
 +        }
-     }
 +
-     @Override
-     public void writeTypeSuffixForArray(final Object o, final JsonGenerator 
jsonGenerator) throws IOException {
-         if (o instanceof List || o instanceof Set) {
-             jsonGenerator.writeEndArray();
-             writeTypeSuffix(jsonGenerator);
-         } else {
-             jsonGenerator.writeEndArray();
-         }
++        return writableTypeId;
 +    }
 +
 +    @Override
 +    protected Class getClassFromObject(final Object o) {
 +        final Class c = o.getClass();
 +        if (classMap.containsKey(c))
 +            return classMap.get(c);
 +
 +        final Class mapped;
 +        if (Map.class.isAssignableFrom(c)) {
 +            if (Tree.class.isAssignableFrom(c))
 +                mapped = Tree.class;
 +            else
 +                mapped = Map.class;
 +        } else if (List.class.isAssignableFrom(c))
 +            mapped = List.class;
 +        else if (Set.class.isAssignableFrom(c))
 +            mapped = Set.class;
 +        else if (Vertex.class.isAssignableFrom(c))
 +            mapped = Vertex.class;
 +        else if (Edge.class.isAssignableFrom(c))
 +            mapped = Edge.class;
 +        else if (Path.class.isAssignableFrom(c))
 +            mapped = Path.class;
 +        else if (VertexProperty.class.isAssignableFrom(c))
 +            mapped = VertexProperty.class;
 +        else if (Metrics.class.isAssignableFrom(c))
 +            mapped = Metrics.class;
 +        else if (TraversalMetrics.class.isAssignableFrom(c))
 +            mapped = TraversalMetrics.class;
 +        else if (Property.class.isAssignableFrom(c))
 +            mapped = Property.class;
 +        else if (ByteBuffer.class.isAssignableFrom(c))
 +            mapped = ByteBuffer.class;
 +        else if (InetAddress.class.isAssignableFrom(c))
 +            mapped = InetAddress.class;
 +        else if (Traverser.class.isAssignableFrom(c))
 +            mapped = Traverser.class;
 +        else if (Lambda.class.isAssignableFrom(c))
 +            mapped = Lambda.class;
 +        else if (VertexProperty.Cardinality.class.isAssignableFrom(c))
 +            mapped = VertexProperty.Cardinality.class;
 +        else if (Column.class.isAssignableFrom(c))
 +            mapped = Column.class;
 +        else if (Direction.class.isAssignableFrom(c))
 +            mapped = Direction.class;
 +        else if (Operator.class.isAssignableFrom(c))
 +            mapped = Operator.class;
 +        else if (Order.class.isAssignableFrom(c))
 +            mapped = Order.class;
 +        else if (Pop.class.isAssignableFrom(c))
 +            mapped = Pop.class;
 +        else if (SackFunctions.Barrier.class.isAssignableFrom(c))
 +            mapped = SackFunctions.Barrier.class;
 +        else if (TraversalOptionParent.Pick.class.isAssignableFrom(c))
 +            mapped = TraversalOptionParent.Pick.class;
 +        else if (Scope.class.isAssignableFrom(c))
 +            mapped = Scope.class;
 +        else if (T.class.isAssignableFrom(c))
 +            mapped = T.class;
 +        else
 +            mapped = c;
 +
 +        classMap.put(c, mapped);
 +        return mapped;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
----------------------------------------------------------------------
diff --cc 
gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
index 7935050,0000000..4e86ebd
mode 100644,000000..100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java
@@@ -1,325 -1,0 +1,358 @@@
 +/*
 + * 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.remote.traversal.DefaultRemoteTraverser;
++import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 +import org.apache.tinkerpop.gremlin.process.traversal.P;
 +import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
++import org.apache.tinkerpop.shaded.jackson.databind.JsonMappingException;
 +import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 +import org.junit.Test;
 +import org.junit.runner.RunWith;
 +import org.junit.runners.Parameterized;
 +
 +import java.io.ByteArrayInputStream;
 +import java.io.ByteArrayOutputStream;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.time.Instant;
 +import java.time.ZoneOffset;
 +import java.time.ZonedDateTime;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.HashMap;
 +import java.util.LinkedHashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.UUID;
 +
 +import static org.hamcrest.MatcherAssert.assertThat;
++import static org.hamcrest.core.IsInstanceOf.instanceOf;
 +import static org.hamcrest.core.StringContains.containsString;
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertNotEquals;
 +import static org.junit.Assert.fail;
 +
 +/**
 + * Tests automatic typed serialization/deserialization for GraphSON 2.0+.
 + *
 + * @author Kevin Gallardo (https://kgdo.me)
 + * @author Stephen Mallette (http://stephen.genoprime.com)
 + */
 +@RunWith(Parameterized.class)
 +public class GraphSONMapperPartialEmbeddedTypeTest extends 
AbstractGraphSONTest {
 +
 +    @Parameterized.Parameters(name = "{0}")
 +    public static Iterable<Object[]> data() {
 +        return Arrays.asList(new Object[][]{
 +                {"v2", GraphSONMapper.build().version(GraphSONVersion.V2_0)
 +                        
.addCustomModule(GraphSONXModuleV2d0.build().create(false))
 +                        
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()},
 +                {"v3", GraphSONMapper.build().version(GraphSONVersion.V3_0)
 +                        
.addCustomModule(GraphSONXModuleV3d0.build().create(false))
 +                        
.typeInfo(TypeInfo.PARTIAL_TYPES).create().createMapper()}
 +        });
 +    }
 +
 +    @Parameterized.Parameter(1)
 +    public ObjectMapper mapper;
 +
 +
 +    @Parameterized.Parameter(0)
 +    public String version;
 +
 +    @Test
++    public void elementOrderShouldNotMatter() throws Exception {
++        final String bytecodeJSONFail1 = 
"{\"@type\":\"g:Bytecode\",\"@value\":{\"step\":[[\"addV\",\"poc_int\"],[\"property\",\"bigint1value\",{\"@type\":\"g:Int32\",\"@value\":-4294967295}]]}}";
++        final String bytecodeJSONFail2 = 
"{\"@value\":{\"step\":[[\"addV\",\"poc_int\"],[\"property\",\"bigint1value\",{\"@value\":-4294967295,\"@type\":\"g:Int32\"}]]},\"@type\":\"g:Bytecode\"}";
++
++        // first validate the failures of TINKERPOP-1738 - prior to the 
jackson fix on 2.9.4 one of these would have
++        // passed based on the ordering of the properties
++        try {
++            mapper.readValue(bytecodeJSONFail1, Bytecode.class);
++            fail("Should have thrown an error because 'bigint1value' is not 
an int32");
++        } catch (Exception ex) {
++            assertThat(ex, instanceOf(JsonMappingException.class));
++        }
++
++        try {
++            mapper.readValue(bytecodeJSONFail2, Bytecode.class);
++            fail("Should have thrown an error because 'bigint1value' is not 
an int32");
++        } catch (Exception ex) {
++            assertThat(ex, instanceOf(JsonMappingException.class));
++        }
++
++        // now do a legit parsing based on order
++        final String bytecodeJSON1 = 
"{\"@type\":\"g:Bytecode\",\"@value\":{\"step\":[[\"addV\",\"poc_int\"],[\"property\",\"bigint1value\",{\"@type\":\"g:Int64\",\"@value\":-4294967295}]]}}";
++        final String bytecodeJSON2 = 
"{\"@value\":{\"step\":[[\"addV\",\"poc_int\"],[\"property\",\"bigint1value\",{\"@value\":-4294967295,\"@type\":\"g:Int64\"}]]},\"@type\":\"g:Bytecode\"}";
++
++        final Bytecode bytecode1 = mapper.readValue(bytecodeJSON1, 
Bytecode.class);
++        final Bytecode bytecode2 = mapper.readValue(bytecodeJSON2, 
Bytecode.class);
++        assertEquals(bytecode1, bytecode2);
++    }
++
++    @Test
 +    public void 
shouldSerializeDeserializeNestedCollectionsAndMapAndTypedValuesCorrectly() 
throws Exception {
 +        // Trying to fail the TypeDeserializer type detection
 +        final UUID uuid = UUID.randomUUID();
 +        final List<Object> myList = new ArrayList<>();
 +
 +        final List<Object> myList2 = new ArrayList<>();
 +        myList2.add(UUID.randomUUID());
 +        myList2.add(33L);
 +        myList2.add(84);
 +        final Map<String,Object> map2 = new HashMap<>();
 +        map2.put("eheh", UUID.randomUUID());
 +        map2.put("normal", "normal");
 +        myList2.add(map2);
 +
 +        final 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());
 +        assertEquals(myList, serializeDeserializeAuto(mapper, myList));
 +
 +        // no "@value" property
 +        String s = "{\""+GraphSONTokens.VALUETYPE+"\":\"" + 
GraphSONTokens.GREMLIN_TYPE_NAMESPACE + ":UUID\", \"test\":2}";
 +        Map<String,Object> map = new LinkedHashMap<>();
 +        map.put(GraphSONTokens.VALUETYPE, 
GraphSONTokens.GREMLIN_TYPE_NAMESPACE + ":UUID");
 +        map.put("test", 2);
 +        Object res = mapper.readValue(s, Object.class);
 +        assertEquals(map, res);
 +
 +        // "@value" and "@type" property reversed
 +        s = "{\""+GraphSONTokens.VALUEPROP+"\":2, \"" + 
GraphSONTokens.VALUETYPE + "\":\"" + GraphSONTokens.GREMLIN_TYPE_NAMESPACE + 
":Int64\"}";
 +        res = mapper.readValue(s, Object.class);
 +        assertEquals(res, 2L);
 +        assertEquals(res.getClass(), Long.class);
 +
 +        // no "@type" property.
 +        s = "{\""+GraphSONTokens.VALUEPROP + "\":2, \"id\":2}";
 +        map = new LinkedHashMap<>();
 +        map.put(GraphSONTokens.VALUEPROP, 2);
 +        map.put("id", 2);
 +        res = mapper.readValue(s, Object.class);
 +        assertEquals(res, map);
 +    }
 +
 +    @Test
 +    public void shouldFailIfMoreThanTwoPropertiesInATypePattern() {
 +        String s = "{\"" + GraphSONTokens.VALUEPROP + "\":2, \"" + 
GraphSONTokens.VALUETYPE + "\":\""+GraphSONTokens.GREMLIN_TYPE_NAMESPACE 
+":Int64\", \"hello\": \"world\"}";
 +        try {
 +            mapper.readValue(s, Object.class);
 +            fail("Should have failed deserializing because there's more than 
properties in the type.");
 +        } catch (IOException e) {
 +            assertThat(e.getMessage(), containsString("Detected the type 
pattern in the JSON payload but the map containing the types and values 
contains other fields. This is not allowed by the deserializer."));
 +        }
 +        s = "{\"" + GraphSONTokens.VALUETYPE + 
"\":\""+GraphSONTokens.GREMLIN_TYPE_NAMESPACE +":Int64\",\"" + 
GraphSONTokens.VALUEPROP + "\":2, \"hello\": \"world\"}";
 +        try {
 +            mapper.readValue(s, Object.class);
 +            fail("Should have failed deserializing because there's more than 
properties in the type.");
 +        } catch (IOException e) {
 +            assertThat(e.getMessage(), containsString("Detected the type 
pattern in the JSON payload but the map containing the types and values 
contains other fields. This is not allowed by the deserializer."));
 +        }
 +    }
 +
 +    @Test
 +    public void shouldFailIfTypeSpecifiedIsNotSameTypeInPayload() {
 +        final ZoneOffset o = ZonedDateTime.now().getOffset();
 +        final ByteArrayOutputStream stream = new ByteArrayOutputStream();
 +        try {
 +            mapper.writeValue(stream, o);
 +            final InputStream inputStream = new 
ByteArrayInputStream(stream.toByteArray());
 +            // What has been serialized is a ZoneOffset with the type, but 
the user explicitly requires another type.
 +            mapper.readValue(inputStream, Instant.class);
 +            fail("Should have failed decoding the value");
 +        } catch (Exception e) {
 +            assertThat(e.getMessage(), containsString("Could not deserialize 
the JSON value as required. Nested exception: java.lang.InstantiationException: 
Cannot deserialize the value with the detected type contained in the JSON ('" + 
GraphSONTokens.GREMLINX_TYPE_NAMESPACE + ":ZoneOffset') to the type specified 
in parameter to the object mapper (class java.time.Instant). Those types are 
incompatible."));
 +        }
 +    }
 +
 +    @Test
 +    public void shouldHandleRawPOJOs() throws Exception {
 +        final FunObject funObject = new FunObject();
 +        funObject.setVal("test");
 +        assertEquals(funObject.toString(), serializeDeserialize(mapper, 
funObject, FunObject.class).toString());
 +        assertEquals(funObject.getClass(), serializeDeserialize(mapper, 
funObject, FunObject.class).getClass());
 +    }
 +
 +    @Test
 +    public void shouldHandleMapWithTypesUsingEmbedTypeSettingV2d0() throws 
Exception {
 +        final ObjectMapper mapper = GraphSONMapper.build()
 +                .version(GraphSONVersion.V2_0)
 +                .typeInfo(TypeInfo.PARTIAL_TYPES)
 +                .create()
 +                .createMapper();
 +
 +        final Map<String,Object> m = new HashMap<>();
 +        m.put("test", 100L);
 +
 +        final String json = mapper.writeValueAsString(m);
 +        final Map read = mapper.readValue(json, HashMap.class);
 +
 +        assertEquals(100L, read.get("test"));
 +    }
 +
 +    @Test
 +    public void shouldNotHandleMapWithTypesUsingEmbedTypeSettingV2d0() throws 
Exception {
 +        final ObjectMapper mapper = GraphSONMapper.build()
 +                .version(GraphSONVersion.V2_0)
 +                .typeInfo(TypeInfo.NO_TYPES)
 +                .create()
 +                .createMapper();
 +
 +        final Map<String,Object> m = new HashMap<>();
 +        m.put("test", 100L);
 +
 +        final String json = mapper.writeValueAsString(m);
 +        final Map read = mapper.readValue(json, HashMap.class);
 +
 +        assertEquals(100, read.get("test"));
 +    }
 +
 +    @Test
 +    public void shouldHandleMapWithTypesUsingEmbedTypeSettingV1d0() throws 
Exception {
 +        final ObjectMapper mapper = GraphSONMapper.build()
 +                .version(GraphSONVersion.V1_0)
 +                .typeInfo(TypeInfo.PARTIAL_TYPES)
 +                .create()
 +                .createMapper();
 +
 +        final Map<String,Object> m = new HashMap<>();
 +        m.put("test", 100L);
 +
 +        final String json = mapper.writeValueAsString(m);
 +        final Map read = mapper.readValue(json, HashMap.class);
 +
 +        assertEquals(100L, read.get("test"));
 +    }
 +
 +    @Test
 +    public void shouldNotHandleMapWithTypesUsingEmbedTypeSettingV1d0() throws 
Exception {
 +        final ObjectMapper mapper = GraphSONMapper.build()
 +                .version(GraphSONVersion.V1_0)
 +                .typeInfo(TypeInfo.NO_TYPES)
 +                .create()
 +                .createMapper();
 +
 +        final Map<String,Object> m = new HashMap<>();
 +        m.put("test", 100L);
 +
 +        final String json = mapper.writeValueAsString(m);
 +        final Map read = mapper.readValue(json, HashMap.class);
 +
 +        assertEquals(100, read.get("test"));
 +    }
 +
 +    @Test
 +    public void shouldLooseTypesInfoWithGraphSONNoType() throws Exception {
 +        final ObjectMapper mapper = GraphSONMapper.build()
 +                .version(GraphSONVersion.V2_0)
 +                .typeInfo(TypeInfo.NO_TYPES)
 +                .create()
 +                .createMapper();
 +
 +        final UUID uuid = UUID.randomUUID();
 +        final List<Object> myList = new ArrayList<>();
 +
 +        final List<Object> myList2 = new ArrayList<>();
 +        myList2.add(UUID.randomUUID());
 +        myList2.add(33L);
 +        myList2.add(84);
 +        final Map<String,Object> map2 = new HashMap<>();
 +        map2.put("eheh", UUID.randomUUID());
 +        map2.put("normal", "normal");
 +        myList2.add(map2);
 +
 +        final 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());
 +
 +        final String json = mapper.writeValueAsString(myList);
 +        final Object read = mapper.readValue(json, Object.class);
 +
 +        // Not equals because of type loss
 +        assertNotEquals(myList, read);
 +    }
 +
 +    @Test
 +    public void shouldHandleDefaultRemoteTraverser() throws Exception {
 +        final DefaultRemoteTraverser<String> o = new 
DefaultRemoteTraverser<>("test", 100);
 +        assertEquals(o, serializeDeserialize(mapper, o, Traverser.class));
 +    }
 +
 +    @Test
 +    public void shouldHandleVariantsOfP() throws Exception {
 +        final List<P> variantsOfP = Arrays.asList(
 +                P.between(1,2),
 +                P.eq(1),
 +                P.gt(1),
 +                P.gte(1),
 +                P.inside(1,2),
 +                P.lt(1),
 +                P.lte(1),
 +                P.neq(1),
 +                P.not(P.eq(1)),
 +                P.outside(1,2),
 +                P.within(1),
 +                P.within(1,2,3,4),
 +                P.within(Arrays.asList(1,2,3,4)),
 +                P.without(1),
 +                P.without(1,2,3,4),
 +                P.without(Arrays.asList(1,2,3,4)),
 +                P.eq(1).and(P.eq(2)),
 +                P.eq(1).or(P.eq(2)));
 +
 +        for (P p : variantsOfP) {
 +            assertEquals(p, serializeDeserialize(mapper, p, P.class));
 +        }
 +    }
 +
 +    // Class needs to be defined as statics as it's a nested class.
 +    public static class FunObject {
 +        private String val;
 +
 +        public FunObject() {
 +        }
 +
 +        public String getVal() {
 +            return this.val;
 +        }
 +
 +        public void setVal(String s) {
 +            this.val = s;
 +        }
 +
 +        public String toString() {
 +            return this.val;
 +        }
 +    }
 +
 +
 +}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a3624f7e/gremlin-shaded/pom.xml
----------------------------------------------------------------------

Reply via email to