private JsonSchema BuildSchema() { if (_reader.TokenType != JsonToken.StartObject) { throw JsonReaderException.Create(_reader, "Expected StartObject while parsing schema object, got {0}.".FormatWith(CultureInfo.InvariantCulture, _reader.TokenType)); } _reader.Read(); // empty schema object if (_reader.TokenType == JsonToken.EndObject) { Push(new JsonSchema()); return(Pop()); } string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); _reader.Read(); // schema reference if (propertyName == JsonSchemaConstants.ReferencePropertyName) { string id = (string)_reader.Value; // skip to the end of the current object while (_reader.Read() && _reader.TokenType != JsonToken.EndObject) { if (_reader.TokenType == JsonToken.StartObject) { throw JsonReaderException.Create(_reader, "Found StartObject within the schema reference with the Id '{0}'".FormatWith(CultureInfo.InvariantCulture, id)); } } JsonSchema referencedSchema = _resolver.GetSchema(id); if (referencedSchema == null) { throw new JsonException("Could not resolve schema reference for Id '{0}'.".FormatWith(CultureInfo.InvariantCulture, id)); } return(referencedSchema); } // regular ol' schema object Push(new JsonSchema()); ProcessSchemaProperty(propertyName); while (_reader.Read() && _reader.TokenType != JsonToken.EndObject) { propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); _reader.Read(); ProcessSchemaProperty(propertyName); } return(Pop()); }
private void ReferenceOrWriteSchema(JsonSchema schema) { if (schema.Id != null && _resolver.GetSchema(schema.Id) != null) { _writer.WriteStartObject(); _writer.WritePropertyName(JsonSchemaConstants.ReferencePropertyName); _writer.WriteValue(schema.Id); _writer.WriteEndObject(); } else { WriteSchema(schema); } }
private JsonSchema GenerateInternal(Type type, Required valueRequired, bool required) { ValidationUtils.ArgumentNotNull(type, "type"); string resolvedId = GetTypeId(type, false); string explicitId = GetTypeId(type, true); if (!string.IsNullOrEmpty(resolvedId)) { JsonSchema resolvedSchema = _resolver.GetSchema(resolvedId); if (resolvedSchema != null) { // resolved schema is not null but referencing member allows nulls // change resolved schema to allow nulls. hacky but what are ya gonna do? if (valueRequired != Required.Always && !HasFlag(resolvedSchema.Type, JsonSchemaType.Null)) { resolvedSchema.Type |= JsonSchemaType.Null; } if (required && resolvedSchema.Required != true) { resolvedSchema.Required = true; } return(resolvedSchema); } } // test for unresolved circular reference if (_stack.Any(tc => tc.Type == type)) { throw new JsonException("Unresolved circular reference for type '{0}'. Explicitly define an Id for the type using a JsonObject/JsonArray attribute or automatically generate a type Id using the UndefinedSchemaIdHandling property.".FormatWith(CultureInfo.InvariantCulture, type)); } JsonContract contract = ContractResolver.ResolveContract(type); JsonConverter converter; if ((converter = contract.Converter) != null || (converter = contract.InternalConverter) != null) { JsonSchema converterSchema = converter.GetSchema(); if (converterSchema != null) { return(converterSchema); } } Push(new TypeSchema(type, new JsonSchema())); if (explicitId != null) { CurrentSchema.Id = explicitId; } if (required) { CurrentSchema.Required = true; } CurrentSchema.Title = GetTitle(type); CurrentSchema.Description = GetDescription(type); if (converter != null) { // todo: Add GetSchema to JsonConverter and use here? CurrentSchema.Type = JsonSchemaType.Any; } else { switch (contract.ContractType) { case JsonContractType.Object: CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); CurrentSchema.Id = GetTypeId(type, false); GenerateObjectSchema(type, (JsonObjectContract)contract); break; case JsonContractType.Array: CurrentSchema.Type = AddNullType(JsonSchemaType.Array, valueRequired); CurrentSchema.Id = GetTypeId(type, false); JsonArrayAttribute arrayAttribute = JsonTypeReflector.GetJsonContainerAttribute(type) as JsonArrayAttribute; bool allowNullItem = (arrayAttribute == null || arrayAttribute.AllowNullItems); Type collectionItemType = ReflectionUtils.GetCollectionItemType(type); if (collectionItemType != null) { CurrentSchema.Items = new List <JsonSchema>(); CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default, false)); } break; case JsonContractType.Primitive: CurrentSchema.Type = GetJsonSchemaType(type, valueRequired); if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum() && !type.IsDefined(typeof(FlagsAttribute), true)) { CurrentSchema.Enum = new List <JToken>(); CurrentSchema.Options = new Dictionary <JToken, string>(); EnumValues <long> enumValues = EnumUtils.GetNamesAndValues <long>(type); foreach (EnumValue <long> enumValue in enumValues) { JToken value = JToken.FromObject(enumValue.Value); CurrentSchema.Enum.Add(value); CurrentSchema.Options.Add(value, enumValue.Name); } } break; case JsonContractType.String: JsonSchemaType schemaType = (!ReflectionUtils.IsNullable(contract.UnderlyingType)) ? JsonSchemaType.String : AddNullType(JsonSchemaType.String, valueRequired); CurrentSchema.Type = schemaType; break; case JsonContractType.Dictionary: CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); Type keyType; Type valueType; ReflectionUtils.GetDictionaryKeyValueTypes(type, out keyType, out valueType); if (keyType != null) { // can be converted to a string if (ConvertUtils.IsConvertible(keyType)) { CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default, false); } } break; #if !(SILVERLIGHT || NETFX_CORE || PORTABLE) case JsonContractType.Serializable: CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); CurrentSchema.Id = GetTypeId(type, false); GenerateISerializableContract(type, (JsonISerializableContract)contract); break; #endif #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE) case JsonContractType.Dynamic: #endif case JsonContractType.Linq: CurrentSchema.Type = JsonSchemaType.Any; break; default: throw new JsonException("Unexpected contract type: {0}".FormatWith(CultureInfo.InvariantCulture, contract)); } } return(Pop().Schema); }