private JsonElement serializeFlatNameValue(
      GraphObject src,
      Type typeOfSrc,
      JsonSerializationContext context,
      String localPropertyView,
      int depth) {

    // prevent endless recursion by pruning at depth 2
    if (depth > outputNestingDepth) {

      return null;
    }

    JsonObject jsonObject = new JsonObject();

    // id (only if idProperty is not set)
    if (idProperty == null) {

      jsonObject.add("id", new JsonPrimitive(src.getId()));

    } else {

      Object idPropertyValue = src.getProperty(idProperty);

      if (idPropertyValue != null) {

        String idString = idPropertyValue.toString();

        jsonObject.add("id", new JsonPrimitive(idString));
      }
    }

    // property keys
    Iterable<String> keys = src.getPropertyKeys(localPropertyView);
    if (keys != null) {
      for (String key : keys) {

        Object value = src.getProperty(key);

        if (value != null) {

          // id property mapping
          if (key.equals(idProperty)) {

            key = "id";
          }

          if (value instanceof Iterable) {

            jsonObject.add(
                key,
                serializeIterable((Iterable) value, typeOfSrc, context, localPropertyView, depth));

          } else if (value instanceof GraphObject) {

            GraphObject graphObject = (GraphObject) value;

            jsonObject.add(
                key,
                this.serializeFlatNameValue(
                    graphObject, typeOfSrc, context, localPropertyView, depth + 1));

          } else if (value instanceof Map) {

            jsonObject.add(
                key,
                serializeMap(
                    (Map) value, typeOfSrc, context, localPropertyView, false, false, depth));

          } else {

            //                                      jsonObject.add(key, new
            // JsonPrimitive(value.toString()));
            jsonObject.add(key, primitive(value));
          }
        } else {

          jsonObject.add(key, new JsonNull());
        }
      }
    }

    return jsonObject;
  }
  // ----- private methods -----
  private JsonElement serializeNestedKeyValueType(
      GraphObject src,
      Type typeOfSrc,
      JsonSerializationContext context,
      boolean includeTypeInOutput,
      String localPropertyView,
      int depth) {

    // prevent endless recursion by pruning at depth 2
    if (depth > outputNestingDepth) {

      return null;
    }

    JsonObject jsonObject = new JsonObject();

    // id (only if idProperty is not set)
    if (idProperty == null) {

      jsonObject.add("id", new JsonPrimitive(src.getId()));

    } else {

      Object idPropertyValue = src.getProperty(idProperty);

      if (idPropertyValue != null) {

        String idString = idPropertyValue.toString();

        jsonObject.add("id", new JsonPrimitive(idString));
      }
    }

    /*
     * String type = src.getType();
     * if (type != null) {
     *
     *       jsonObject.add("type", new JsonPrimitive(type));
     *
     * }
     */

    // property keys
    JsonArray properties = new JsonArray();

    for (String key : src.getPropertyKeys(localPropertyView)) {

      Object value = src.getProperty(key);

      if (value instanceof Iterable) {

        JsonArray property = new JsonArray();

        for (Object o : (Iterable) value) {

          if (o instanceof GraphObject) {

            GraphObject obj = (GraphObject) o;
            JsonElement recursiveSerializedValue =
                this.serializeNestedKeyValueType(
                    obj, typeOfSrc, context, includeTypeInOutput, localPropertyView, depth + 1);

            if (recursiveSerializedValue != null) {

              property.add(recursiveSerializedValue);
            }

          } else if (o instanceof Map) {

            properties.add(
                serializeMap(
                    (Map) o,
                    typeOfSrc,
                    context,
                    localPropertyView,
                    includeTypeInOutput,
                    true,
                    depth));

          } else {

            // serialize primitive, this is for PropertyNotion
            properties.add(serializePrimitive(key, o, includeTypeInOutput));
          }

          // TODO: Unterstützung von Notions mit mehr als einem Property bei der Ausgabe!
          // => neuer Typ?

        }

        properties.add(property);

      } else if (value instanceof GraphObject) {

        GraphObject graphObject = (GraphObject) value;

        properties.add(
            this.serializeNestedKeyValueType(
                graphObject,
                typeOfSrc,
                context,
                includeTypeInOutput,
                localPropertyView,
                depth + 1));

      } else if (value instanceof Map) {

        properties.add(
            serializeMap(
                (Map) value,
                typeOfSrc,
                context,
                localPropertyView,
                includeTypeInOutput,
                true,
                depth));

      } else {

        properties.add(serializePrimitive(key, value, includeTypeInOutput));
      }
    }

    jsonObject.add("properties", properties);

    if (src instanceof AbstractNode) {

      // outgoing relationships
      Map<RelationshipType, Long> outRelStatistics =
          ((AbstractNode) src).getRelationshipInfo(Direction.OUTGOING);

      if (outRelStatistics != null) {

        JsonArray outRels = new JsonArray();

        for (Entry<RelationshipType, Long> entry : outRelStatistics.entrySet()) {

          RelationshipType relType = entry.getKey();
          Long count = entry.getValue();
          JsonObject outRelEntry = new JsonObject();

          outRelEntry.add("type", new JsonPrimitive(relType.name()));
          outRelEntry.add("count", new JsonPrimitive(count));
          outRels.add(outRelEntry);
        }

        jsonObject.add("out", outRels);
      }

      // incoming relationships
      Map<RelationshipType, Long> inRelStatistics =
          ((AbstractNode) src).getRelationshipInfo(Direction.INCOMING);

      if (inRelStatistics != null) {

        JsonArray inRels = new JsonArray();

        for (Entry<RelationshipType, Long> entry : inRelStatistics.entrySet()) {

          RelationshipType relType = entry.getKey();
          Long count = entry.getValue();
          JsonObject inRelEntry = new JsonObject();

          inRelEntry.add("type", new JsonPrimitive(relType.name()));
          inRelEntry.add("count", new JsonPrimitive(count));
          inRels.add(inRelEntry);
        }

        jsonObject.add("in", inRels);
      }
    } else if (src instanceof AbstractRelationship) {

      // start node id (for relationships)
      String startNodeId = ((AbstractRelationship) src).getStartNodeId();

      if (startNodeId != null) {

        jsonObject.add("startNodeId", new JsonPrimitive(startNodeId));
      }

      // end node id (for relationships)
      String endNodeId = ((AbstractRelationship) src).getEndNodeId();

      if (endNodeId != null) {

        jsonObject.add("endNodeId", new JsonPrimitive(endNodeId));
      }
    }

    return jsonObject;
  }