public ObjectNode getObject(
     String key, ObjectNode node, boolean required, String location, ParseResult result) {
   JsonNode value = node.get(key);
   ObjectNode on = null;
   if (value == null) {
     if (required) {
       result.missing(location, key);
       result.invalid();
     }
   } else if (!value.getNodeType().equals(JsonNodeType.OBJECT)) {
     result.invalidType(location, key, "object", value);
     if (required) {
       result.invalid();
     }
   } else {
     on = (ObjectNode) value;
   }
   return on;
 }
 public String getString(
     String key, ObjectNode node, boolean required, String location, ParseResult result) {
   String value = null;
   JsonNode v = node.get(key);
   if (node == null || v == null) {
     if (required) {
       result.missing(location, key);
       result.invalid();
     }
   } else {
     value = v.asText();
   }
   return value;
 }
 public Integer getInteger(
     String key, ObjectNode node, boolean required, String location, ParseResult result) {
   Integer value = null;
   JsonNode v = node.get(key);
   if (node == null || v == null) {
     if (required) {
       result.missing(location, key);
       result.invalid();
     }
   } else if (v.getNodeType().equals(JsonNodeType.NUMBER)) {
     value = v.intValue();
   }
   return value;
 }
 public ArrayNode getArray(
     String key, ObjectNode node, boolean required, String location, ParseResult result) {
   JsonNode value = node.get(key);
   ArrayNode an = null;
   if (value == null) {
     if (required) {
       result.missing(location, key);
       result.invalid();
     }
   } else if (!value.getNodeType().equals(JsonNodeType.ARRAY)) {
     result.invalidType(location, key, "array", value);
   } else {
     an = (ArrayNode) value;
   }
   return an;
 }
 public Boolean getBoolean(
     String key, ObjectNode node, boolean required, String location, ParseResult result) {
   Boolean value = null;
   JsonNode v = node.get(key);
   if (node == null || v == null) {
     if (required) {
       result.missing(location, key);
       result.invalid();
     }
   } else {
     if (v.getNodeType().equals(JsonNodeType.BOOLEAN)) {
       value = v.asBoolean();
     } else if (v.getNodeType().equals(JsonNodeType.STRING)) {
       String stringValue = v.textValue();
       return Boolean.parseBoolean(stringValue);
     }
   }
   return value;
 }
  public Swagger parseRoot(JsonNode node, ParseResult result) {
    String location = "";
    Swagger swagger = new Swagger();
    if (node.getNodeType().equals(JsonNodeType.OBJECT)) {
      ObjectNode on = (ObjectNode) node;
      Iterator<JsonNode> it = null;

      // required
      String value = getString("swagger", on, true, location, result);
      swagger.setSwagger(value);

      ObjectNode obj = getObject("info", on, true, "", result);
      if (obj != null) {
        Info info = info(obj, "info", result);
        swagger.info(info);
      }

      // optional
      value = getString("host", on, false, location, result);
      swagger.setHost(value);

      value = getString("basePath", on, false, location, result);
      swagger.setBasePath(value);

      ArrayNode array = getArray("schemes", on, false, location, result);
      if (array != null) {
        it = array.iterator();
        while (it.hasNext()) {
          JsonNode n = it.next();
          String s = getString(n, location + ".schemes", result);
          if (s != null) {
            Scheme scheme = Scheme.forValue(s);
            if (scheme != null) {
              swagger.scheme(scheme);
            }
          }
        }
      }

      array = getArray("consumes", on, false, location, result);
      if (array != null) {
        it = array.iterator();
        while (it.hasNext()) {
          JsonNode n = it.next();
          String s = getString(n, location + ".consumes", result);
          if (s != null) {
            swagger.consumes(s);
          }
        }
      }

      array = getArray("produces", on, false, location, result);
      if (array != null) {
        it = array.iterator();
        while (it.hasNext()) {
          JsonNode n = it.next();
          String s = getString(n, location + ".produces", result);
          if (s != null) {
            swagger.produces(s);
          }
        }
      }

      obj = getObject("paths", on, true, location, result);
      Map<String, Path> paths = paths(obj, "paths", result);
      swagger.paths(paths);

      obj = getObject("definitions", on, false, location, result);
      Map<String, Model> definitions = definitions(obj, "definitions", result);
      swagger.setDefinitions(definitions);

      obj = getObject("parameters", on, false, location, result);
      // TODO: parse
      Map<String, Parameter> parameters =
          Json.mapper()
              .convertValue(
                  obj,
                  Json.mapper()
                      .getTypeFactory()
                      .constructMapType(Map.class, String.class, Parameter.class));
      swagger.setParameters(parameters);

      obj = getObject("responses", on, false, location, result);
      Map<String, Response> responses = responses(obj, "responses", result);
      swagger.responses(responses);

      obj = getObject("securityDefinitions", on, false, location, result);
      Map<String, SecuritySchemeDefinition> securityDefinitions =
          securityDefinitions(obj, location, result);
      swagger.setSecurityDefinitions(securityDefinitions);

      array = getArray("security", on, false, location, result);
      List<SecurityRequirement> security = securityRequirements(array, location, result);
      swagger.setSecurity(security);

      array = getArray("tags", on, false, location, result);
      List<Tag> tags = tags(array, location, result);
      swagger.tags(tags);

      obj = getObject("externalDocs", on, false, location, result);
      ExternalDocs docs = externalDocs(obj, location, result);
      swagger.externalDocs(docs);

      // extra keys
      Set<String> keys = getKeys(on);
      for (String key : keys) {
        if (key.startsWith("x-")) {
          swagger.vendorExtension(key, extension(on.get(key)));
        } else if (!ROOT_KEYS.contains(key)) {
          result.extra(location, key, node.get(key));
        }
      }
    } else {
      result.invalidType("", "", "object", node);
      result.invalid();
      return null;
    }
    return swagger;
  }