org.sonar.core.graph.graphson.GraphsonUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.core.graph.graphson.GraphsonUtil.java

Source

/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * SonarQube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.core.graph.graphson;

import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Vertex;
import org.apache.commons.io.Charsets;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import javax.annotation.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

import static org.sonar.core.graph.graphson.ElementPropertyConfig.ElementPropertiesRule;

/**
 * Helps write individual graph elements to TinkerPop JSON format known as GraphSON.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
class GraphsonUtil {

    private final GraphsonMode mode;
    private final Set<String> vertexPropertyKeys;
    private final Set<String> edgePropertyKeys;
    private final ElementFactory factory;
    private final boolean hasEmbeddedTypes;
    private final ElementPropertiesRule vertexPropertiesRule;
    private final ElementPropertiesRule edgePropertiesRule;
    private final boolean includeReservedVertexId;
    private final boolean includeReservedEdgeId;
    private final boolean includeReservedVertexType;
    private final boolean includeReservedEdgeType;
    private final boolean includeReservedEdgeLabel;
    private final boolean includeReservedEdgeOutV;
    private final boolean includeReservedEdgeInV;
    private JSONParser parser = new JSONParser();

    /**
     * A GraphSONUtiltiy that includes all properties of vertices and edges.
     */
    GraphsonUtil(GraphsonMode mode, ElementFactory factory) {
        this(mode, factory, ElementPropertyConfig.AllProperties);
    }

    /**
     * A GraphSONUtility that includes the specified properties.
     */
    GraphsonUtil(GraphsonMode mode, ElementFactory factory, Set<String> vertexPropertyKeys,
            Set<String> edgePropertyKeys) {
        this(mode, factory, ElementPropertyConfig.includeProperties(vertexPropertyKeys, edgePropertyKeys));
    }

    GraphsonUtil(GraphsonMode mode, ElementFactory factory, ElementPropertyConfig config) {
        this.vertexPropertyKeys = config.getVertexPropertyKeys();
        this.edgePropertyKeys = config.getEdgePropertyKeys();
        this.vertexPropertiesRule = config.getVertexPropertiesRule();
        this.edgePropertiesRule = config.getEdgePropertiesRule();

        this.mode = mode;
        this.factory = factory;
        this.hasEmbeddedTypes = mode == GraphsonMode.EXTENDED;

        this.includeReservedVertexId = includeReservedKey(mode, GraphsonTokens._ID, vertexPropertyKeys,
                this.vertexPropertiesRule);
        this.includeReservedEdgeId = includeReservedKey(mode, GraphsonTokens._ID, edgePropertyKeys,
                this.edgePropertiesRule);
        this.includeReservedVertexType = includeReservedKey(mode, GraphsonTokens._TYPE, vertexPropertyKeys,
                this.vertexPropertiesRule);
        this.includeReservedEdgeType = includeReservedKey(mode, GraphsonTokens._TYPE, edgePropertyKeys,
                this.edgePropertiesRule);
        this.includeReservedEdgeLabel = includeReservedKey(mode, GraphsonTokens._LABEL, edgePropertyKeys,
                this.edgePropertiesRule);
        this.includeReservedEdgeOutV = includeReservedKey(mode, GraphsonTokens._OUT_V, edgePropertyKeys,
                this.edgePropertiesRule);
        this.includeReservedEdgeInV = includeReservedKey(mode, GraphsonTokens._IN_V, edgePropertyKeys,
                this.edgePropertiesRule);
    }

    /**
     * Creates a JSONObject from a graph element.
     *
     * @param element      the graph element to convert to JSON.
     * @param propertyKeys The property keys at the root of the element to serialize.  If null, then all keys are serialized.
     * @param mode         the type of GraphSON to be generated.
     */
    static JSONObject jsonFromElement(Element element, @Nullable Set<String> propertyKeys, GraphsonMode mode) {
        GraphsonUtil graphson = element instanceof Edge ? new GraphsonUtil(mode, null, null, propertyKeys)
                : new GraphsonUtil(mode, null, propertyKeys, null);
        return graphson.jsonFromElement(element);
    }

    /**
     * Reads an individual Vertex from JSON.  The vertex must match the accepted GraphSON format.
     *
     * @param json         a single vertex in GraphSON format as JSONObject
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include on reading of element properties
     */
    static Vertex vertexFromJson(JSONObject json, ElementFactory factory, GraphsonMode mode,
            Set<String> propertyKeys) throws IOException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, propertyKeys, null);
        return graphson.vertexFromJson(json);
    }

    /**
     * Reads an individual Vertex from JSON.  The vertex must match the accepted GraphSON format.
     *
     * @param json         a single vertex in GraphSON format as a String.
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include on reading of element properties
     */
    static Vertex vertexFromJson(String json, ElementFactory factory, GraphsonMode mode, Set<String> propertyKeys)
            throws ParseException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, propertyKeys, null);
        return graphson.vertexFromJson(json);
    }

    /**
     * Reads an individual Vertex from JSON.  The vertex must match the accepted GraphSON format.
     *
     * @param json         a single vertex in GraphSON format as an InputStream.
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include on reading of element properties
     */
    static Vertex vertexFromJson(InputStream json, ElementFactory factory, GraphsonMode mode,
            Set<String> propertyKeys) throws IOException, ParseException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, propertyKeys, null);
        return graphson.vertexFromJson(json);
    }

    private static boolean includeReservedKey(GraphsonMode mode, String key, Set<String> propertyKeys,
            ElementPropertiesRule rule) {
        // the key is always included in modes other than compact. if it is compact, then validate that the
        // key is in the property key list
        return mode != GraphsonMode.COMPACT || includeKey(key, propertyKeys, rule);
    }

    private static boolean includeKey(String key, Set<String> propertyKeys, ElementPropertiesRule rule) {
        if (propertyKeys == null) {
            // when null always include the key and shortcut this piece
            return true;
        }

        // default the key situation. if it's included then it should be explicitly defined in the
        // property keys list to be included or the reverse otherwise
        boolean keySituation = rule == ElementPropertiesRule.INCLUDE;

        if (rule == ElementPropertiesRule.INCLUDE) {
            keySituation = propertyKeys.contains(key);
        } else if (rule == ElementPropertiesRule.EXCLUDE) {
            keySituation = !propertyKeys.contains(key);
        }
        return keySituation;
    }

    /**
     * Reads an individual Edge from JSON.  The edge must match the accepted GraphSON format.
     *
     * @param json         a single edge in GraphSON format as a String
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include when reading of element properties
     */
    static Edge edgeFromJson(String json, Vertex out, Vertex in, ElementFactory factory, GraphsonMode mode,
            Set<String> propertyKeys) throws IOException, ParseException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, null, propertyKeys);
        return graphson.edgeFromJson(json, out, in);
    }

    /**
     * Reads an individual Edge from JSON.  The edge must match the accepted GraphSON format.
     *
     * @param json         a single edge in GraphSON format as an InputStream
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include when reading of element properties
     */
    static Edge edgeFromJson(InputStream json, Vertex out, Vertex in, ElementFactory factory, GraphsonMode mode,
            Set<String> propertyKeys) throws IOException, ParseException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, null, propertyKeys);
        return graphson.edgeFromJson(json, out, in);
    }

    /**
     * Reads an individual Edge from JSON.  The edge must match the accepted GraphSON format.
     *
     * @param json         a single edge in GraphSON format as a JSONObject
     * @param factory      the factory responsible for constructing graph elements
     * @param mode         the mode of the GraphSON
     * @param propertyKeys a list of keys to include when reading of element properties
     */
    static Edge edgeFromJson(JSONObject json, Vertex out, Vertex in, ElementFactory factory, GraphsonMode mode,
            Set<String> propertyKeys) throws IOException {
        GraphsonUtil graphson = new GraphsonUtil(mode, factory, null, propertyKeys);
        return graphson.edgeFromJson(json, out, in);
    }

    static Map<String, Object> readProperties(JSONObject node, boolean ignoreReservedKeys,
            boolean hasEmbeddedTypes) {
        Map<String, Object> map = new HashMap<String, Object>();

        for (Object objKey : node.keySet()) {
            String key = (String) objKey;
            Object value = node.get(key);

            if (!ignoreReservedKeys || !isReservedKey(key)) {
                map.put(key, readProperty(value, hasEmbeddedTypes));
            }
        }

        return map;
    }

    private static boolean isReservedKey(String key) {
        return key.equals(GraphsonTokens._ID) || key.equals(GraphsonTokens._TYPE)
                || key.equals(GraphsonTokens._LABEL) || key.equals(GraphsonTokens._OUT_V)
                || key.equals(GraphsonTokens._IN_V);
    }

    private static JSONArray createJSONList(List list, Set<String> propertyKeys, boolean showTypes) {
        JSONArray jsonList = new JSONArray();
        for (Object item : list) {
            if (item instanceof Element) {
                jsonList.add(jsonFromElement((Element) item, propertyKeys,
                        showTypes ? GraphsonMode.EXTENDED : GraphsonMode.NORMAL));
            } else if (item instanceof List) {
                jsonList.add(createJSONList((List) item, propertyKeys, showTypes));
            } else if (item instanceof Map) {
                jsonList.add(createJSONMap((Map) item, propertyKeys, showTypes));
            } else if (item != null && item.getClass().isArray()) {
                jsonList.add(createJSONList(convertArrayToList(item), propertyKeys, showTypes));
            } else if (item instanceof Set) {
                throw new UnsupportedOperationException("Set property is not supported");
            } else {
                addObject(jsonList, item);
            }
        }
        return jsonList;
    }

    //
    private static JSONObject createJSONMap(Map<Object, Object> map, Set<String> propertyKeys, boolean showTypes) {
        JSONObject jsonMap = new JSONObject();
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            Object value = entry.getValue();
            if (value != null) {
                if (value instanceof List) {
                    value = createJSONList((List) value, propertyKeys, showTypes);
                } else if (value instanceof Map) {
                    value = createJSONMap((Map) value, propertyKeys, showTypes);
                } else if (value instanceof Element) {
                    value = jsonFromElement((Element) value, propertyKeys,
                            showTypes ? GraphsonMode.EXTENDED : GraphsonMode.NORMAL);
                } else if (value.getClass().isArray()) {
                    value = createJSONList(convertArrayToList(value), propertyKeys, showTypes);
                }
            }

            putObject(jsonMap, entry.getKey().toString(), getValue(value, showTypes));
        }
        return jsonMap;

    }

    private static Object readProperty(Object node, boolean hasEmbeddedTypes) {
        Object propertyValue;

        if (hasEmbeddedTypes) {
            JSONObject json = (JSONObject) node;
            if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_UNKNOWN)) {
                propertyValue = null;
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_BOOLEAN)) {
                propertyValue = json.get(GraphsonTokens.VALUE);
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_FLOAT)) {
                propertyValue = ((Double) json.get(GraphsonTokens.VALUE)).floatValue();
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_DOUBLE)) {
                propertyValue = json.get(GraphsonTokens.VALUE);
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_INTEGER)) {
                propertyValue = ((Long) json.get(GraphsonTokens.VALUE)).intValue();
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_LONG)) {
                propertyValue = json.get(GraphsonTokens.VALUE);
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_STRING)) {
                propertyValue = json.get(GraphsonTokens.VALUE);
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_LIST)) {
                propertyValue = readProperties(((JSONArray) json.get(GraphsonTokens.VALUE)).iterator(),
                        hasEmbeddedTypes);
            } else if (json.get(GraphsonTokens.TYPE).equals(GraphsonTokens.TYPE_MAP)) {
                propertyValue = readProperties((JSONObject) json.get(GraphsonTokens.VALUE), false,
                        hasEmbeddedTypes);
            } else {
                propertyValue = node.toString();
            }
        } else {
            if (node == null) {
                propertyValue = null;
            } else if (node instanceof Boolean) {
                propertyValue = node;
            } else if (node instanceof Double) {
                propertyValue = node;
            } else if (node instanceof Integer) {
                propertyValue = node;
            } else if (node instanceof Long) {
                propertyValue = node;
            } else if (node instanceof String) {
                propertyValue = node;
            } else if (node instanceof JSONArray) {
                propertyValue = readProperties(((JSONArray) node).iterator(), hasEmbeddedTypes);
            } else if (node instanceof JSONObject) {
                propertyValue = readProperties((JSONObject) node, false, hasEmbeddedTypes);
            } else {
                propertyValue = node;
            }
        }

        return propertyValue;
    }

    private static void putObject(JSONObject jsonMap, String key, Object value) {
        if (value == null) {
            jsonMap.put(key, null);
        } else if (value instanceof Boolean) {
            jsonMap.put(key, value);
        } else if (value instanceof Long) {
            jsonMap.put(key, value);
        } else if (value instanceof Integer) {
            jsonMap.put(key, value);
        } else if (value instanceof Float) {
            jsonMap.put(key, value);
        } else if (value instanceof Double) {
            jsonMap.put(key, value);
        } else if (value instanceof String) {
            jsonMap.put(key, value);
        } else if (value instanceof JSONObject) {
            jsonMap.put(key, value);
        } else if (value instanceof JSONArray) {
            jsonMap.put(key, value);
        } else {
            jsonMap.put(key, value.toString());
        }
    }

    private static List readProperties(Iterator<JSONObject> listOfNodes, boolean hasEmbeddedTypes) {
        List array = new ArrayList();

        while (listOfNodes.hasNext()) {
            array.add(readProperty(listOfNodes.next(), hasEmbeddedTypes));
        }

        return array;
    }

    private static void addObject(JSONArray jsonList, Object value) {
        if (value == null) {
            jsonList.add(null);
        } else if (value instanceof Boolean) {
            jsonList.add(value);
        } else if (value instanceof Long) {
            jsonList.add(value);
        } else if (value instanceof Integer) {
            jsonList.add(value);
        } else if (value instanceof Float) {
            jsonList.add(value);
        } else if (value instanceof Double) {
            jsonList.add(value);
        } else if (value instanceof String) {
            jsonList.add(value);
        } else if (value instanceof JSONObject) {
            jsonList.add(value);
        } else if (value instanceof JSONArray) {
            jsonList.add(value);
        } else {
            jsonList.add(value.toString());
        }
    }

    private static Map createPropertyMap(Element element, Set<String> propertyKeys, ElementPropertiesRule rule) {
        Map map = new HashMap<String, Object>();

        if (propertyKeys == null) {
            for (String key : element.getPropertyKeys()) {
                map.put(key, element.getProperty(key));
            }
        } else {
            if (rule == ElementPropertiesRule.INCLUDE) {
                for (String key : propertyKeys) {
                    Object valToPutInMap = element.getProperty(key);
                    if (valToPutInMap != null) {
                        map.put(key, valToPutInMap);
                    }
                }
            } else {
                for (String key : element.getPropertyKeys()) {
                    if (!propertyKeys.contains(key)) {
                        map.put(key, element.getProperty(key));
                    }
                }
            }
        }

        return map;
    }

    private static Object getValue(Object value, boolean includeType) {

        Object returnValue = value;

        // if the includeType is set to true then show the data types of the properties
        if (includeType) {

            // type will be one of: map, list, string, long, int, double, float.
            // in the event of a complex object it will call a toString and store as a
            // string
            String type = determineType(value);

            JSONObject valueAndType = new JSONObject();
            valueAndType.put(GraphsonTokens.TYPE, type);

            if (type.equals(GraphsonTokens.TYPE_LIST)) {

                // values of lists must be accumulated as ObjectNode objects under the value key.
                // will return as a ArrayNode. called recursively to traverse the entire
                // object graph of each item in the array.
                JSONArray list = (JSONArray) value;

                // there is a set of values that must be accumulated as an array under a key
                JSONArray valueArray = new JSONArray();
                valueAndType.put(GraphsonTokens.VALUE, valueArray);
                for (int ix = 0; ix < list.size(); ix++) {
                    // the value of each item in the array is a node object from an ArrayNode...must
                    // get the value of it.
                    addObject(valueArray, getValue(list.get(ix), includeType));
                }

            } else if (type.equals(GraphsonTokens.TYPE_MAP)) {

                // maps are converted to a ObjectNode. called recursively to traverse
                // the entire object graph within the map.
                JSONObject convertedMap = new JSONObject();
                JSONObject jsonObject = (JSONObject) value;

                Map<Object, Object> jsonObjectMap = jsonObject;
                for (Map.Entry<Object, Object> entry : jsonObjectMap.entrySet()) {

                    // no need to getValue() here as this is already a ObjectNode and should have type info
                    convertedMap.put(entry.getKey(), entry.getValue());
                }

                valueAndType.put(GraphsonTokens.VALUE, convertedMap);

            } else {

                // this must be a primitive value or a complex object. if a complex
                // object it will be handled by a call to toString and stored as a
                // string value
                putObject(valueAndType, GraphsonTokens.VALUE, value);
            }

            // this goes back as a JSONObject with data type and value
            returnValue = valueAndType;
        }

        return returnValue;
    }

    private static List convertArrayToList(Object value) {

        // is there seriously no better way to do this...bah!
        List list = new ArrayList();
        if (value instanceof int[]) {
            int[] arr = (int[]) value;
            for (int ix = 0; ix < arr.length; ix++) {
                list.add(arr[ix]);
            }
        } else if (value instanceof double[]) {
            double[] arr = (double[]) value;
            for (int ix = 0; ix < arr.length; ix++) {
                list.add(arr[ix]);
            }
        } else if (value instanceof float[]) {
            float[] arr = (float[]) value;
            for (int ix = 0; ix < arr.length; ix++) {
                list.add(arr[ix]);
            }
        } else if (value instanceof long[]) {
            long[] arr = (long[]) value;
            for (int ix = 0; ix < arr.length; ix++) {
                list.add(arr[ix]);
            }
        } else if (value instanceof boolean[]) {
            boolean[] arr = (boolean[]) value;
            for (int ix = 0; ix < arr.length; ix++) {
                list.add(arr[ix]);
            }
        } else {
            list = Arrays.asList((Object[]) value);
        }

        return list;
    }

    private static String determineType(Object value) {
        String type = GraphsonTokens.TYPE_STRING;
        if (value == null) {
            type = "unknown";
        } else if (value instanceof Double) {
            type = GraphsonTokens.TYPE_DOUBLE;
        } else if (value instanceof Float) {
            type = GraphsonTokens.TYPE_FLOAT;
        } else if (value instanceof Integer) {
            type = GraphsonTokens.TYPE_INTEGER;
        } else if (value instanceof Long) {
            type = GraphsonTokens.TYPE_LONG;
        } else if (value instanceof Boolean) {
            type = GraphsonTokens.TYPE_BOOLEAN;
        } else if (value instanceof JSONArray) {
            type = GraphsonTokens.TYPE_LIST;
        } else if (value instanceof JSONObject) {
            type = GraphsonTokens.TYPE_MAP;
        }

        return type;
    }

    /**
     * Creates a vertex from GraphSON using settings supplied in the constructor.
     */
    Vertex vertexFromJson(InputStream json) throws ParseException, IOException {
        return this.vertexFromJson((JSONObject) parser.parse(new InputStreamReader(json, Charsets.UTF_8)));
    }

    /**
     * Creates an edge from GraphSON using settings supplied in the constructor.
     */
    Edge edgeFromJson(String json, Vertex out, Vertex in) throws IOException, ParseException {
        return this.edgeFromJson((JSONObject) parser.parse(json), out, in);
    }

    /**
     * Creates an edge from GraphSON using settings supplied in the constructor.
     */
    Edge edgeFromJson(InputStream json, Vertex out, Vertex in) throws IOException, ParseException {
        return this.edgeFromJson((JSONObject) parser.parse(new InputStreamReader(json, Charsets.UTF_8)), out, in);
    }

    /**
     * Creates an edge from GraphSON using settings supplied in the constructor.
     */
    Edge edgeFromJson(JSONObject json, Vertex out, Vertex in) throws IOException {
        Map<String, Object> props = GraphsonUtil.readProperties(json, true, this.hasEmbeddedTypes);

        Object edgeId = json.get(GraphsonTokens._ID);

        Object nodeLabel = json.get(GraphsonTokens._LABEL);
        String label = nodeLabel == null ? null : nodeLabel.toString();

        Edge e = factory.createEdge(edgeId, out, in, label);

        for (Map.Entry<String, Object> entry : props.entrySet()) {
            if (includeKey(entry.getKey(), edgePropertyKeys, this.edgePropertiesRule)) {
                e.setProperty(entry.getKey(), entry.getValue());
            }
        }

        return e;
    }

    /**
     * Creates a vertex from GraphSON using settings supplied in the constructor.
     */
    Vertex vertexFromJson(String json) throws ParseException {
        return this.vertexFromJson((JSONObject) parser.parse(json));
    }

    /**
     * Creates a vertex from GraphSON using settings supplied in the constructor.
     */
    Vertex vertexFromJson(JSONObject json) {
        Map<String, Object> props = readProperties(json, true, this.hasEmbeddedTypes);

        Object vertexId = json.get(GraphsonTokens._ID);
        Vertex v = factory.createVertex(vertexId);

        for (Map.Entry<String, Object> entry : props.entrySet()) {
            if (includeKey(entry.getKey(), vertexPropertyKeys, this.vertexPropertiesRule)) {
                v.setProperty(entry.getKey(), entry.getValue());
            }
        }

        return v;
    }

    /**
     * Creates GraphSON for a single graph element.
     */
    JSONObject jsonFromElement(Element element) {
        boolean isEdge = element instanceof Edge;
        boolean showTypes = mode == GraphsonMode.EXTENDED;
        Set<String> propertyKeys = isEdge ? this.edgePropertyKeys : this.vertexPropertyKeys;
        ElementPropertiesRule elementPropertyConfig = isEdge ? this.edgePropertiesRule : this.vertexPropertiesRule;

        JSONObject jsonElement = createJSONMap(createPropertyMap(element, propertyKeys, elementPropertyConfig),
                propertyKeys, showTypes);

        if ((isEdge && this.includeReservedEdgeId) || (!isEdge && this.includeReservedVertexId)) {
            putObject(jsonElement, GraphsonTokens._ID, element.getId());
        }

        // it's important to keep the order of these straight. check Edge first and then Vertex because there
        // are graph implementations that have Edge extend from Vertex
        if (element instanceof Edge) {
            Edge edge = (Edge) element;

            if (this.includeReservedEdgeId) {
                putObject(jsonElement, GraphsonTokens._ID, element.getId());
            }

            if (this.includeReservedEdgeType) {
                jsonElement.put(GraphsonTokens._TYPE, GraphsonTokens.EDGE);
            }

            if (this.includeReservedEdgeOutV) {
                putObject(jsonElement, GraphsonTokens._OUT_V, edge.getVertex(Direction.OUT).getId());
            }

            if (this.includeReservedEdgeInV) {
                putObject(jsonElement, GraphsonTokens._IN_V, edge.getVertex(Direction.IN).getId());
            }

            if (this.includeReservedEdgeLabel) {
                jsonElement.put(GraphsonTokens._LABEL, edge.getLabel());
            }
        } else if (element instanceof Vertex) {
            if (this.includeReservedVertexId) {
                putObject(jsonElement, GraphsonTokens._ID, element.getId());
            }

            if (this.includeReservedVertexType) {
                jsonElement.put(GraphsonTokens._TYPE, GraphsonTokens.VERTEX);
            }
        }

        return jsonElement;
    }
}