public List<SecurityRequirement> securityRequirements(
      ArrayNode node, String location, ParseResult result) {
    if (node == null) return null;

    List<SecurityRequirement> output = new ArrayList<SecurityRequirement>();

    for (JsonNode item : node) {
      SecurityRequirement security = new SecurityRequirement();
      if (item.getNodeType().equals(JsonNodeType.OBJECT)) {
        ObjectNode on = (ObjectNode) item;
        Set<String> keys = getKeys(on);

        for (String key : keys) {
          List<String> scopes = new ArrayList<>();
          ArrayNode obj = getArray(key, on, false, location + ".security", result);
          if (obj != null) {
            for (JsonNode n : obj) {
              if (n.getNodeType().equals(JsonNodeType.STRING)) {
                scopes.add(n.asText());
              } else {
                result.invalidType(location, key, "string", n);
              }
            }
          }
          security.requirement(key, scopes);
        }
      }
      output.add(security);
    }

    return output;
  }
  public Model allOfModel(ObjectNode node, String location, ParseResult result) {
    JsonNode sub = node.get("$ref");
    JsonNode allOf = node.get("allOf");

    if (sub != null) {
      if (sub.getNodeType().equals(JsonNodeType.OBJECT)) {
        return refModel((ObjectNode) sub, location, result);
      } else {
        result.invalidType(location, "$ref", "object", sub);
        return null;
      }
    } else if (allOf != null) {
      ComposedModel model = null;
      // we only support one parent, no multiple inheritance or composition
      if (allOf.getNodeType().equals(JsonNodeType.ARRAY)) {
        model = new ComposedModel();
        int pos = 0;
        for (JsonNode part : allOf) {
          if (part.getNodeType().equals(JsonNodeType.OBJECT)) {
            Model segment = definition((ObjectNode) part, location, result);
            if (segment != null) {
              model.getAllOf().add(segment);
            }
          } else {
            result.invalidType(location, "allOf[" + pos + "]", "object", part);
          }
          pos++;
        }

        List<Model> allComponents = model.getAllOf();
        if (allComponents.size() >= 1) {
          model.setParent(allComponents.get(0));
          if (allComponents.size() >= 2) {
            model.setChild(allComponents.get(allComponents.size() - 1));
            List<RefModel> interfaces = new ArrayList<RefModel>();
            int size = allComponents.size();
            for (Model m : allComponents.subList(1, size - 1)) {
              if (m instanceof RefModel) {
                RefModel ref = (RefModel) m;
                interfaces.add(ref);
              }
            }
            model.setInterfaces(interfaces);
          } else {
            model.setChild(new ModelImpl());
          }
        }
        return model;
      } else {
        result.invalidType(location, "allOf", "array", allOf);
      }

      return model;
    }
    return null;
  }
 public Object extension(JsonNode jsonNode) {
   if (jsonNode.getNodeType().equals(JsonNodeType.BOOLEAN)) {
     return jsonNode.asBoolean();
   }
   if (jsonNode.getNodeType().equals(JsonNodeType.STRING)) {
     return jsonNode.asText();
   }
   if (jsonNode.getNodeType().equals(JsonNodeType.NUMBER)) {
     NumericNode n = (NumericNode) jsonNode;
     if (n.isLong()) {
       return jsonNode.asLong();
     }
     if (n.isInt()) {
       return jsonNode.asInt();
     }
     if (n.isBigDecimal()) {
       return jsonNode.textValue();
     }
     if (n.isBoolean()) {
       return jsonNode.asBoolean();
     }
     if (n.isFloat()) {
       return jsonNode.floatValue();
     }
     if (n.isDouble()) {
       return jsonNode.doubleValue();
     }
     if (n.isShort()) {
       return jsonNode.intValue();
     }
     return jsonNode.asText();
   }
   if (jsonNode.getNodeType().equals(JsonNodeType.ARRAY)) {
     ArrayNode an = (ArrayNode) jsonNode;
     List<Object> o = new ArrayList<Object>();
     for (JsonNode i : an) {
       Object obj = extension(i);
       if (obj != null) {
         o.add(obj);
       }
     }
     return o;
   }
   return jsonNode;
 }
 public String getString(JsonNode node, String location, ParseResult result) {
   String output = null;
   if (!node.getNodeType().equals(JsonNodeType.STRING)) {
     result.invalidType(location, "", "string", node);
   } else {
     output = ((TextNode) node).asText();
   }
   return output;
 }
  public Response response(ObjectNode node, String location, ParseResult result) {
    if (node == null) return null;

    Response output = new Response();
    JsonNode ref = node.get("$ref");
    if (ref != null) {
      if (ref.getNodeType().equals(JsonNodeType.STRING)) {
        return refResponse((TextNode) ref, location, result);
      } else {
        result.invalidType(location, "$ref", "string", node);
        return null;
      }
    }

    String value = getString("description", node, true, location, result);
    output.description(value);

    ObjectNode schema = getObject("schema", node, false, location, result);
    if (schema != null) {
      output.schema(Json.mapper().convertValue(schema, Property.class));
    }
    ObjectNode headersNode = getObject("headers", node, false, location, result);
    if (headersNode != null) {
      // TODO
      Map<String, Property> headers =
          Json.mapper()
              .convertValue(
                  headersNode,
                  Json.mapper()
                      .getTypeFactory()
                      .constructMapType(Map.class, String.class, Property.class));
      output.headers(headers);
    }

    ObjectNode examplesNode = getObject("examples", node, false, location, result);
    if (examplesNode != null) {
      Map<String, Object> examples =
          Json.mapper()
              .convertValue(
                  examplesNode,
                  Json.mapper()
                      .getTypeFactory()
                      .constructMapType(Map.class, String.class, Object.class));
      output.setExamples(examples);
    }

    // extra keys
    Set<String> keys = getKeys(node);
    for (String key : keys) {
      if (key.startsWith("x-")) {
        output.setVendorExtension(key, extension(node.get(key)));
      } else if (!RESPONSE_KEYS.contains(key)) {
        result.extra(location, key, node.get(key));
      }
    }
    return output;
  }
 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;
 }
 @Override
 public ObjectId deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
   JsonNode node = jp.readValueAsTree();
   if (node == null) {
     return null;
   }
   if (node.getNodeType() == JsonNodeType.OBJECT) {
     return new ObjectId(node.get("$oid").asText());
   }
   return new ObjectId(node.textValue());
 }
  public List<String> tagStrings(ArrayNode nodes, String location, ParseResult result) {
    if (nodes == null) return null;

    List<String> output = new ArrayList<String>();

    for (JsonNode node : nodes) {
      if (node.getNodeType().equals(JsonNodeType.STRING)) {
        output.add(node.textValue());
      }
    }
    return output;
  }
 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;
 }
 @Override
 JsonNode computeNode(JsonPathContext context, JsonNode[] childValues) {
   JsonNode o = childValues[0];
   JsonNode i = index.eval(context).asNode();
   if (i.isTextual()) {
     if (!o.isObject()) {
       throw new JsonPathRuntimeException(
           "field selector must apply on an object, not a "
               + o.getNodeType().toString().toLowerCase(),
           position);
     }
     return o.path(asString(i, "index of selector"));
   }
   if (i.isNumber()) {
     if (!o.isArray()) {
       throw new JsonPathRuntimeException(
           "field selector must apply on an array, not a "
               + o.getNodeType().toString().toLowerCase(),
           position);
     }
     int n = i.asInt();
     if (n >= o.size()) {
       throw new JsonPathRuntimeException(
           "index out of bound " + n + " > " + (o.size() - 1), position);
     }
     if (n < -o.size()) {
       throw new JsonPathRuntimeException(
           "index out of bound " + n + " < " + (-o.size()), position);
     }
     if (n < 0) {
       return o.get(o.size() + n);
     }
     return o.get(n);
   }
   throw new TypeMismatchException(position, JsonNodeType.NUMBER, o, "the index of the array");
 }
 public List<Parameter> parameters(ArrayNode obj, String location, ParseResult result) {
   List<Parameter> output = new ArrayList<Parameter>();
   if (obj == null) {
     return output;
   }
   for (JsonNode item : obj) {
     if (item.getNodeType().equals(JsonNodeType.OBJECT)) {
       Parameter param = parameter((ObjectNode) item, location, result);
       if (param != null) {
         output.add(param);
       }
     }
   }
   return output;
 }
  public List<Tag> tags(ArrayNode nodes, String location, ParseResult result) {
    if (nodes == null) return null;

    List<Tag> output = new ArrayList<Tag>();

    for (JsonNode node : nodes) {
      if (node.getNodeType().equals(JsonNodeType.OBJECT)) {
        Tag tag = tag((ObjectNode) node, location + ".tags", result);
        if (tag != null) {
          output.add(tag);
        }
      }
    }

    return output;
  }
 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;
 }
  private static Object convertToConnect(Schema schema, JsonNode jsonValue) {
    JsonToConnectTypeConverter typeConverter;
    final Schema.Type schemaType;
    if (schema != null) {
      schemaType = schema.type();
    } else {
      switch (jsonValue.getNodeType()) {
        case NULL:
          // Special case. With no schema
          return null;
        case BOOLEAN:
          schemaType = Schema.Type.BOOLEAN;
          break;
        case NUMBER:
          if (jsonValue.isIntegralNumber()) schemaType = Schema.Type.INT64;
          else schemaType = Schema.Type.FLOAT64;
          break;
        case ARRAY:
          schemaType = Schema.Type.ARRAY;
          break;
        case OBJECT:
          schemaType = Schema.Type.MAP;
          break;
        case STRING:
          schemaType = Schema.Type.STRING;
          break;

        case BINARY:
        case MISSING:
        case POJO:
        default:
          schemaType = null;
          break;
      }
    }
    typeConverter = TO_CONNECT_CONVERTERS.get(schemaType);
    if (typeConverter == null) throw new DataException("Unknown schema type: " + schema.type());

    Object converted = typeConverter.convert(schema, jsonValue);
    if (schema != null && schema.name() != null) {
      LogicalTypeConverter logicalConverter = TO_CONNECT_LOGICAL_CONVERTERS.get(schema.name());
      if (logicalConverter != null) converted = logicalConverter.convert(schema, converted);
    }
    return converted;
  }
  public Map<String, Property> properties(ObjectNode node, String location, ParseResult result) {
    if (node == null) {
      return null;
    }
    Map<String, Property> output = new LinkedHashMap<String, Property>();

    Set<String> keys = getKeys(node);
    for (String propertyName : keys) {
      JsonNode propertyNode = node.get(propertyName);
      if (propertyNode.getNodeType().equals(JsonNodeType.OBJECT)) {
        Property property = property((ObjectNode) propertyNode, location, result);
        output.put(propertyName, property);
      } else {
        result.invalidType(location, propertyName, "object", propertyNode);
      }
    }
    return output;
  }
  public Map<String, Model> definitions(ObjectNode node, String location, ParseResult result) {
    if (node == null) return null;
    Set<String> schemas = getKeys(node);
    Map<String, Model> output = new LinkedHashMap<String, Model>();

    for (String schemaName : schemas) {
      JsonNode schema = node.get(schemaName);
      if (schema.getNodeType().equals(JsonNodeType.OBJECT)) {
        Model model = definition((ObjectNode) schema, location + "." + schemaName, result);
        if (model != null) {
          output.put(schemaName, model);
        }
      } else {
        result.invalidType(location, schemaName, "object", schema);
      }
    }
    return output;
  }
  @Test
  public void testGetTasks() throws Exception {
    Response response = target("/tasks").request().get();
    assertResponseStatus(response, Response.Status.OK);
    assertHeader(
        response.getHeaders(), HttpHeaders.CONTENT_TYPE, JsonApiMediaType.APPLICATION_JSON_API);

    JsonNode data = mapper.readTree((InputStream) response.getEntity()).get("data");
    assertThat(data.getNodeType(), is(JsonNodeType.ARRAY));
    List<Task> tasks = new ArrayList<>();
    for (JsonNode node : data) {
      tasks.add(getTaskFromJson(node));
    }
    assertThat(tasks, hasSize(1));
    final Task task = tasks.get(0);
    assertThat(task.getId(), is(1L));
    assertThat(task.getName(), is("First task"));
    assertThat(task.getProject(), is(nullValue()));
  }
  public Map<String, Path> paths(ObjectNode obj, String location, ParseResult result) {
    Map<String, Path> output = new LinkedHashMap<>();
    if (obj == null) {
      return null;
    }

    Set<String> pathKeys = getKeys(obj);
    for (String pathName : pathKeys) {
      JsonNode pathValue = obj.get(pathName);
      if (!pathValue.getNodeType().equals(JsonNodeType.OBJECT)) {
        result.invalidType(location, pathName, "object", pathValue);
      } else {
        ObjectNode path = (ObjectNode) pathValue;
        Path pathObj = path(path, location + ".'" + pathName + "'", result);
        output.put(pathName, pathObj);
      }
    }
    return output;
  }
 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;
 }
Beispiel #20
0
 public static Object toObject(JsonNode node) throws IOException {
   JsonNodeType type = node.getNodeType();
   switch (type) {
     case ARRAY:
       List<Object> list = new ArrayList<>();
       for (JsonNode child : node) {
         list.add(toObject(child));
       }
       return list;
     case BINARY:
       return node.binaryValue();
     case BOOLEAN:
       return node.booleanValue();
     case NULL:
       return null;
     case NUMBER:
       return node.numberValue();
     case OBJECT:
     case POJO:
       return toMap(node);
     default:
       return node.textValue();
   }
 }
  public Path path(ObjectNode obj, String location, ParseResult result) {
    boolean hasRef = false;
    Path output = null;
    if (obj.get("$ref") != null) {
      JsonNode ref = obj.get("$ref");
      if (ref.getNodeType().equals(JsonNodeType.STRING)) {
        return pathRef((TextNode) ref, location, result);
      } else if (ref.getNodeType().equals(JsonNodeType.OBJECT)) {
        ObjectNode on = (ObjectNode) ref;

        // extra keys
        Set<String> keys = getKeys(on);
        for (String key : keys) {
          result.extra(location, key, on.get(key));
        }
      }
      return null;
    }
    Path path = new Path();

    ArrayNode parameters = getArray("parameters", obj, false, location, result);
    path.setParameters(parameters(parameters, location, result));

    ObjectNode on = getObject("get", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(get)", result);
      if (op != null) {
        path.setGet(op);
      }
    }
    on = getObject("put", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(put)", result);
      if (op != null) {
        path.setPut(op);
      }
    }
    on = getObject("post", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(post)", result);
      if (op != null) {
        path.setPost(op);
      }
    }
    on = getObject("head", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(head)", result);
      if (op != null) {
        path.setHead(op);
      }
    }
    on = getObject("delete", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(delete)", result);
      if (op != null) {
        path.setDelete(op);
      }
    }
    on = getObject("patch", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(patch)", result);
      if (op != null) {
        path.setPatch(op);
      }
    }
    on = getObject("options", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(options)", result);
      if (op != null) {
        path.setOptions(op);
      }
    }

    // extra keys
    Set<String> keys = getKeys(obj);
    for (String key : keys) {
      if (key.startsWith("x-")) {
        path.setVendorExtension(key, extension(obj.get(key)));
      } else if (!PATH_KEYS.contains(key)) {
        result.extra(location, key, obj.get(key));
      }
    }
    return path;
  }
  public Parameter parameter(ObjectNode obj, String location, ParseResult result) {
    if (obj == null) {
      return null;
    }

    Parameter output = null;
    JsonNode ref = obj.get("$ref");
    if (ref != null) {
      if (ref.getNodeType().equals(JsonNodeType.STRING)) {
        return refParameter((TextNode) ref, location, result);
      } else {
        result.invalidType(location, "$ref", "string", obj);
        return null;
      }
    }

    String l = null;
    JsonNode ln = obj.get("name");
    if (ln != null) {
      l = ln.asText();
    } else {
      l = "['unknown']";
    }
    location += ".[" + l + "]";

    String value = getString("in", obj, true, location, result);
    if (value != null) {
      String type = getString("type", obj, false, location, result);
      String format = getString("format", obj, false, location, result);
      AbstractSerializableParameter<?> sp = null;
      if ("query".equals(value)) {
        sp = new QueryParameter();
      } else if ("header".equals(value)) {
        sp = new HeaderParameter();
      } else if ("path".equals(value)) {
        sp = new PathParameter();
      } else if ("formData".equals(value)) {
        sp = new FormParameter();
      }

      if (sp != null) {
        // type is mandatory when sp != null
        getString("type", obj, true, location, result);
        Map<PropertyBuilder.PropertyId, Object> map =
            new HashMap<PropertyBuilder.PropertyId, Object>();

        map.put(TYPE, type);
        map.put(FORMAT, format);
        String defaultValue = getString("default", obj, false, location, result);
        map.put(DEFAULT, defaultValue);
        sp.setDefault(defaultValue);

        Double dbl = getDouble("maximum", obj, false, location, result);
        if (dbl != null) {
          map.put(MAXIMUM, dbl);
          sp.setMaximum(dbl);
        }

        Boolean bl = getBoolean("exclusiveMaximum", obj, false, location, result);
        if (bl != null) {
          map.put(EXCLUSIVE_MAXIMUM, bl);
          sp.setExclusiveMaximum(bl);
        }

        dbl = getDouble("minimum", obj, false, location, result);
        if (dbl != null) {
          map.put(MINIMUM, dbl);
          sp.setMinimum(dbl);
        }

        bl = getBoolean("exclusiveMinimum", obj, false, location, result);
        if (bl != null) {
          map.put(EXCLUSIVE_MINIMUM, bl);
          sp.setExclusiveMinimum(bl);
        }

        map.put(MAX_LENGTH, getInteger("maxLength", obj, false, location, result));
        map.put(MIN_LENGTH, getInteger("minLength", obj, false, location, result));

        String pat = getString("pattern", obj, false, location, result);
        map.put(PATTERN, pat);
        sp.setPattern(pat);

        Integer iv = getInteger("maxItems", obj, false, location, result);
        map.put(MAX_ITEMS, iv);
        sp.setMaxItems(iv);

        iv = getInteger("minItems", obj, false, location, result);
        map.put(MIN_ITEMS, iv);
        sp.setMinItems(iv);

        map.put(UNIQUE_ITEMS, getBoolean("uniqueItems", obj, false, location, result));

        ArrayNode an = getArray("enum", obj, false, location, result);
        if (an != null) {
          List<String> _enum = new ArrayList<String>();
          for (JsonNode n : an) {
            _enum.add(n.textValue());
          }
          sp.setEnum(_enum);
          map.put(ENUM, _enum);
        }

        Property prop = PropertyBuilder.build(type, format, map);

        if (prop != null) {
          sp.setProperty(prop);
          ObjectNode items = getObject("items", obj, false, location, result);
          if (items != null) {
            Property inner = schema(null, items, location, result);
            sp.setItems(inner);
          }
        }

        Set<String> keys = getKeys(obj);
        for (String key : keys) {
          if (key.startsWith("x-")) {
            sp.setVendorExtension(key, extension(obj.get(key)));
          } else if (!PARAMETER_KEYS.contains(key)) {
            result.extra(location, key, obj.get(key));
          }
        }

        String collectionFormat = getString("collectionFormat", obj, false, location, result);
        sp.setCollectionFormat(collectionFormat);

        output = sp;
      } else if ("body".equals(value)) {
        output = Json.mapper().convertValue(obj, Parameter.class);
      }
      if (output != null) {
        value = getString("name", obj, true, location, result);
        output.setName(value);

        value = getString("description", obj, false, location, result);
        output.setDescription(value);

        Boolean required = getBoolean("required", obj, false, location, result);
        if (required != null) {
          output.setRequired(required);
        }
      }
    }

    return output;
  }
  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;
  }
  public Model definition(ObjectNode node, String location, ParseResult result) {
    if (node == null) {
      result.missing(location, "empty schema");
    }
    if (node.get("$ref") != null) {
      return refModel(node, location, result);
    }
    if (node.get("allOf") != null) {
      return allOfModel(node, location, result);
    }
    Model model = null;
    String value = null;

    String type = getString("type", node, false, location, result);
    Model m = new ModelImpl();
    if ("array".equals(type)) {
      ArrayModel am = new ArrayModel();
      ObjectNode propertyNode = getObject("properties", node, false, location, result);
      Map<String, Property> properties = properties(propertyNode, location, result);
      am.setProperties(properties);

      ObjectNode itemsNode = getObject("items", node, false, location, result);
      Property items = property(itemsNode, location, result);
      if (items != null) {
        am.items(items);
      }

      model = am;
    } else {
      ModelImpl impl = new ModelImpl();
      impl.setType(value);

      JsonNode ap = node.get("additionalProperties");
      if (ap != null && ap.getNodeType().equals(JsonNodeType.OBJECT)) {
        impl.setAdditionalProperties(Json.mapper().convertValue(ap, Property.class));
      }

      value = getString("default", node, false, location, result);
      impl.setDefaultValue(value);

      value = getString("format", node, false, location, result);
      impl.setFormat(value);

      value = getString("discriminator", node, false, location, result);
      impl.setDiscriminator(value);

      JsonNode xml = node.get("xml");
      if (xml != null) {
        impl.setXml(Json.mapper().convertValue(xml, Xml.class));
      }

      ObjectNode externalDocs = getObject("externalDocs", node, false, location, result);
      ExternalDocs docs = externalDocs(externalDocs, location, result);
      impl.setExternalDocs(docs);

      ObjectNode properties = getObject("properties", node, true, location, result);
      if (properties != null) {
        Set<String> propertyNames = getKeys(properties);
        for (String propertyName : propertyNames) {
          JsonNode propertyNode = properties.get(propertyName);
          if (propertyNode.getNodeType().equals(JsonNodeType.OBJECT)) {
            ObjectNode on = (ObjectNode) propertyNode;
            Property property = property(on, location, result);
            impl.property(propertyName, property);
          } else {
            result.invalidType(location, "properties", "object", propertyNode);
          }
        }
      }

      // need to set properties first
      ArrayNode required = getArray("required", node, false, location, result);
      if (required != null) {
        List<String> requiredProperties = new ArrayList<String>();
        for (JsonNode n : required) {
          if (n.getNodeType().equals(JsonNodeType.STRING)) {
            requiredProperties.add(((TextNode) n).textValue());
          } else {
            result.invalidType(location, "required", "string", n);
          }
        }
        if (requiredProperties.size() > 0) {
          impl.setRequired(requiredProperties);
        }
      }

      // extra keys
      Set<String> keys = getKeys(node);
      for (String key : keys) {
        if (key.startsWith("x-")) {
          impl.setVendorExtension(key, extension(node.get(key)));
        } else if (!SCHEMA_KEYS.contains(key)) {
          result.extra(location, key, node.get(key));
        }
      }
      if ("{ }".equals(Json.pretty(impl))) return null;
      model = impl;
    }
    JsonNode exampleNode = node.get("example");
    if (exampleNode != null) {
      // we support text or object nodes
      if (exampleNode.getNodeType().equals(JsonNodeType.OBJECT)) {
        ObjectNode on = getObject("example", node, false, location, result);
        if (on != null) {
          model.setExample(on);
        }
      } else {
        model.setExample(exampleNode.asText());
      }
    }

    if (model != null) {
      value = getString("description", node, false, location, result);
      model.setDescription(value);

      value = getString("title", node, false, location, result);
      model.setTitle(value);
    }

    return model;
  }