blob: 2cd57dcec70814fbc4572d01d6c6ec6a1f39f2ff [file] [log] [blame]
/*
* 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.BulkSet;
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 WritableTypeId writeTypePrefix(final JsonGenerator jsonGenerator, final WritableTypeId writableTypeId) throws IOException {
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 if (canWriteTypeId()) {
writeTypePrefix(jsonGenerator, getTypeIdResolver().idFromValueAndType(writableTypeId.forValue, getClassFromObject(writableTypeId.forValue)));
} else {
throw new IllegalStateException("Could not write prefix: shape[" + writableTypeId.valueShape + "] value[" + writableTypeId.forValue + "]");
}
return writableTypeId;
}
@Override
public WritableTypeId writeTypeSuffix(final JsonGenerator jsonGenerator, final WritableTypeId writableTypeId) throws IOException {
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 if (canWriteTypeId()) {
writeTypeSuffix(jsonGenerator);
} else {
throw new IllegalStateException("Could not write suffix: shape[" + writableTypeId.valueShape + "] value[" + writableTypeId.forValue + "]");
}
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) || BulkSet.class.isAssignableFrom(c)) // coerce BulkSet to List as their behavior on iteration is identical
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;
}
}