private void buildTypeDefinition(IMetaObject meta) {
    if (typeMap.containsKey(meta.getName())) return;

    typeMap.put(meta.getName(), "type" + typeCounter);
    JSONObject def = new JSONObject();
    definitions.put("type" + typeCounter, def);
    typeCounter += 1;

    def.put("type", "object");
    JSONObject properties = new JSONObject();
    def.put("properties", properties);

    for (IMetaPrimitive prim : meta.getMetaPrimitives()) {
      JSONObject type = primitiveToJSONType(prim.getType());
      if (type != null) properties.put(prim.getName(), type);
    }

    for (IMetaAssociation assoc : meta.getMetaAssociationsParent()) {
      JSONObject type = associationToJSONType(assoc);
      if (type != null) properties.put(assoc.getName().split("\\.")[1], type);
    }
  }
  private JSONObject associationToJSONType(IMetaAssociation assoc) {
    IMetaObject child = assoc.getChild();

    JSONObject type = null;

    // some kind of foreign key
    if (child.isPersistable()) {
      // only if there is a service available for that type;
      if (RestServices.getServiceForEntity(child.getName()) != null) {
        type =
            new JSONObject()
                .put("type", "string")
                .put("title", String.format("Reference to a(n) '%s'", child.getName()));
      }
    }

    // persistent object, describe this object in the service as well
    else {
      buildTypeDefinition(child); // make sure the type is available in the schema
      String targetType = typeMap.get(child.getName());
      type = new JSONObject().put("$ref", "#/definitions/" + targetType);
      if ("type1".equals(targetType)) hasReferenceToRoot = true;
    }

    // assoc should be included?
    if (type == null) return null;

    // make sure referencesets require arrays
    if (assoc.getType() == AssociationType.REFERENCESET)
      type = new JSONObject().put("type", "array").put("items", type);

    // make sure null refs are supported
    else /* not a refset */ type = orNull(type);

    return type;
  }
  private void consistencyCheck() throws CoreException {
    String secError = ConsistencyChecker.checkAccessRole(this.roleOrMicroflow);
    if (secError != null)
      throw new IllegalArgumentException(
          "Cannot publish microflow " + microflowname + ": " + secError);

    int argCount = Utils.getArgumentTypes(microflowname).size();

    if (argCount > 1)
      throw new IllegalArgumentException(
          "Cannot publish microflow "
              + microflowname
              + ", it should exist and have exactly zero or one argument");

    hasArgument = argCount == 1;

    List<String> pathParams = new UriTemplate(relativeUrl).getTemplateVariables();
    if (pathParams.size() > 0 && !hasArgument) {
      throw new IllegalArgumentException(
          "Cannot publish microflow "
              + microflowname
              + " with path '"
              + relativeUrl
              + ", the microflow should have a single input argument object with at least attributes "
              + pathParams);
    }

    if (hasArgument) {
      IDataType argtype = Utils.getFirstArgumentType(microflowname);
      if (!argtype.isMendixObject())
        throw new IllegalArgumentException(
            "Cannot publish microflow "
                + microflowname
                + ", it should have a single object as input argument");
      this.argType = argtype.getObjectType();
      this.argName = Utils.getArgumentTypes(microflowname).keySet().iterator().next();
      isFileSource = Core.isSubClassOf(FileDocument.entityName, argType);

      IMetaObject metaObject = Core.getMetaObject(argType);
      if (metaObject.isPersistable() && !isFileSource)
        throw new IllegalArgumentException(
            "Cannot publish microflow "
                + microflowname
                + ", it should have a transient object of filedocument as input argument");

      Set<String> metaPrimitiveNames = Sets.newHashSet();
      for (IMetaPrimitive prim : metaObject.getMetaPrimitives()) {
        metaPrimitiveNames.add(prim.getName().toLowerCase());
      }
      for (String pathParam : pathParams) {
        if (!metaPrimitiveNames.contains(pathParam.toLowerCase()))
          throw new IllegalArgumentException(
              "Cannot publish microflow "
                  + microflowname
                  + ", its input argument should have an attribute with name '"
                  + pathParam
                  + "', as required by the template path");
      }
    }

    if (httpMethod == null) {
      throw new IllegalArgumentException(
          "Cannot publish microflow " + microflowname + ", it has no HTTP method defined.");
    }

    IDataType returnTypeFromMF = Core.getReturnType(microflowname);

    if (returnTypeFromMF.isMendixObject() || returnTypeFromMF.isList()) {
      this.returnType = returnTypeFromMF.getObjectType();
      isFileTarget = Core.isSubClassOf(FileDocument.entityName, this.returnType);

      if (Core.getMetaObject(this.returnType).isPersistable() && !isFileTarget)
        throw new IllegalArgumentException(
            "Cannot publish microflow "
                + microflowname
                + ", its return type should be a non-persistable object or a file document");
    } else isReturnTypePrimitive = true;
  }