private JsonSchema BuildSchema() { if (_reader.TokenType != JsonToken.StartObject) { throw new Exception("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 new Exception("Found StartObject within the schema reference with the Id '{0}'" .FormatWith(CultureInfo.InvariantCulture, id)); } } JsonSchema referencedSchema = _resolver.GetSchema(id); if (referencedSchema == null) { throw new Exception("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 BuildSchema() { if (_reader.TokenType != JsonToken.StartObject) { throw new Exception("Expected StartObject while parsing schema object, got {0}.".FormatWith(CultureInfo.InvariantCulture, _reader.TokenType)); } _reader.Read(); if (_reader.TokenType == JsonToken.EndObject) { Push(new JsonSchema()); return(Pop()); } string text = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); _reader.Read(); if (text == "$ref") { string text2 = (string)_reader.Value; while (_reader.Read() && _reader.TokenType != JsonToken.EndObject) { if (_reader.TokenType == JsonToken.StartObject) { throw new Exception("Found StartObject within the schema reference with the Id '{0}'".FormatWith(CultureInfo.InvariantCulture, text2)); } } JsonSchema schema = _resolver.GetSchema(text2); if (schema == null) { throw new Exception("Could not resolve schema reference for Id '{0}'.".FormatWith(CultureInfo.InvariantCulture, text2)); } return(schema); } Push(new JsonSchema()); ProcessSchemaProperty(text); while (_reader.Read() && _reader.TokenType != JsonToken.EndObject) { text = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); _reader.Read(); ProcessSchemaProperty(text); } return(Pop()); }
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 Exception("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 (typeof(IConvertible).IsAssignableFrom(keyType)) { CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default, false); } } break; #if !SILVERLIGHT && !PocketPC 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) case JsonContractType.Dynamic: #endif case JsonContractType.Linq: CurrentSchema.Type = JsonSchemaType.Any; break; default: throw new Exception("Unexpected contract type: {0}".FormatWith(CultureInfo.InvariantCulture, contract)); } } return(Pop().Schema); }
private JsonSchema ResolveReferences(JsonSchema schema) { if (schema.DeferredReference != null) { string reference = schema.DeferredReference; bool locationReference = (reference.StartsWith("#", StringComparison.Ordinal)); if (locationReference) { reference = UnescapeReference(reference); } JsonSchema resolvedSchema = _resolver.GetSchema(reference); if (resolvedSchema == null) { if (locationReference) { string[] escapedParts = schema.DeferredReference .TrimStart('#') .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); JToken currentToken = _rootSchema; foreach (string escapedPart in escapedParts) { string part = UnescapeReference(escapedPart); if (currentToken.Type == JTokenType.Object) { currentToken = currentToken[part]; } else if ( currentToken.Type == JTokenType.Array || currentToken.Type == JTokenType.Constructor ) { if ( int.TryParse(part, out int index) && index >= 0 && index < currentToken.Count() ) { currentToken = currentToken[index]; } else { currentToken = null; } } if (currentToken == null) { break; } } if (currentToken != null) { resolvedSchema = BuildSchema(currentToken); } } if (resolvedSchema == null) { throw new JsonException( "Could not resolve schema reference '{0}'.".FormatWith( CultureInfo.InvariantCulture, schema.DeferredReference ) ); } } schema = resolvedSchema; } if (schema.ReferencesResolved) { return(schema); } schema.ReferencesResolved = true; if (schema.Extends != null) { for (int i = 0; i < schema.Extends.Count; i++) { schema.Extends[i] = ResolveReferences(schema.Extends[i]); } } if (schema.Items != null) { for (int i = 0; i < schema.Items.Count; i++) { schema.Items[i] = ResolveReferences(schema.Items[i]); } } if (schema.AdditionalItems != null) { schema.AdditionalItems = ResolveReferences(schema.AdditionalItems); } if (schema.PatternProperties != null) { foreach ( KeyValuePair < string, JsonSchema > patternProperty in schema.PatternProperties.ToList() ) { schema.PatternProperties[patternProperty.Key] = ResolveReferences( patternProperty.Value ); } } if (schema.Properties != null) { foreach (KeyValuePair <string, JsonSchema> property in schema.Properties.ToList()) { schema.Properties[property.Key] = ResolveReferences(property.Value); } } if (schema.AdditionalProperties != null) { schema.AdditionalProperties = ResolveReferences(schema.AdditionalProperties); } return(schema); }
private JsonSchema GenerateInternal(Type type, Required valueRequired) { 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) { return(resolvedSchema); } } // test for unresolved circular reference if (_stack.Any(tc => tc.Type == type)) { throw new Exception("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)); } Push(new TypeSchema(type, new JsonSchema())); if (explicitId != null) { CurrentSchema.Id = explicitId; } CurrentSchema.Title = GetTitle(type); CurrentSchema.Description = GetDescription(type); if (CollectionUtils.IsDictionaryType(type)) { // TODO: include null CurrentSchema.Type = JsonSchemaType.Object; Type keyType; Type valueType; ReflectionUtils.GetDictionaryKeyValueTypes(type, out keyType, out valueType); if (keyType != null) { // can be converted to a string if (typeof(IConvertible).IsAssignableFrom(keyType)) { CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default); } } } else if (CollectionUtils.IsCollectionType(type)) { // TODO: include null CurrentSchema.Type = JsonSchemaType.Array; CurrentSchema.Id = GetTypeId(type, false); JsonArrayAttribute arrayAttribute = JsonTypeReflector.GetJsonContainerAttribute(type) as JsonArrayAttribute; bool allowNullItem = (arrayAttribute != null) ? arrayAttribute.AllowNullItems : false; Type collectionItemType = ReflectionUtils.GetCollectionItemType(type); if (collectionItemType != null) { CurrentSchema.Items = new List <JsonSchema>(); CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default)); } } else { CurrentSchema.Type = GetJsonSchemaType(type, valueRequired); if (HasFlag(CurrentSchema.Type, JsonSchemaType.Object)) { CurrentSchema.Id = GetTypeId(type, false); JsonObjectContract contract = ContractResolver.ResolveContract(type) as JsonObjectContract; if (contract == null) { throw new Exception("Could not resolve contract for '{0}'.".FormatWith(CultureInfo.InvariantCulture, type)); } CurrentSchema.Properties = new Dictionary <string, JsonSchema>(); foreach (JsonProperty property in contract.Properties) { if (!property.Ignored) { JsonSchema propertySchema = GenerateInternal(property.PropertyType, property.Required); if (property.DefaultValue != null) { propertySchema.Default = JToken.FromObject(property.DefaultValue); } CurrentSchema.Properties.Add(property.PropertyName, propertySchema); } } if (type.IsSealed) { CurrentSchema.AllowAdditionalProperties = false; } } else 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); } } } return(Pop().Schema); }
private JsonSchema GenerateInternal(Type type, Required valueRequired, bool required) { ValidationUtils.ArgumentNotNull(type, "type"); string typeId = GetTypeId(type, explicitOnly: false); string typeId2 = GetTypeId(type, explicitOnly: true); if (!string.IsNullOrEmpty(typeId)) { JsonSchema schema = _resolver.GetSchema(typeId); if (schema != null) { if (valueRequired != Required.Always && !HasFlag(schema.Type, JsonSchemaType.Null)) { schema.Type |= JsonSchemaType.Null; } if (required && schema.Required != true) { schema.Required = true; } return(schema); } } if (_stack.Any((TypeSchema tc) => tc.Type == type)) { throw new Exception("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 jsonContract = ContractResolver.ResolveContract(type); JsonConverter jsonConverter; if ((jsonConverter = jsonContract.Converter) != null || (jsonConverter = jsonContract.InternalConverter) != null) { JsonSchema schema2 = jsonConverter.GetSchema(); if (schema2 != null) { return(schema2); } } Push(new TypeSchema(type, new JsonSchema())); if (typeId2 != null) { CurrentSchema.Id = typeId2; } if (required) { CurrentSchema.Required = true; } CurrentSchema.Title = GetTitle(type); CurrentSchema.Description = GetDescription(type); if (jsonConverter != null) { CurrentSchema.Type = JsonSchemaType.Any; } else if (jsonContract is JsonDictionaryContract) { CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); ReflectionUtils.GetDictionaryKeyValueTypes(type, out Type keyType, out Type valueType); if (keyType != null && typeof(IConvertible).IsAssignableFrom(keyType)) { CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default, required: false); } } else if (jsonContract is JsonArrayContract) { CurrentSchema.Type = AddNullType(JsonSchemaType.Array, valueRequired); CurrentSchema.Id = GetTypeId(type, explicitOnly: false); bool flag = (JsonTypeReflector.GetJsonContainerAttribute(type) as JsonArrayAttribute)?.AllowNullItems ?? true; Type collectionItemType = ReflectionUtils.GetCollectionItemType(type); if (collectionItemType != null) { CurrentSchema.Items = new List <JsonSchema>(); CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!flag) ? Required.Always : Required.Default, required: false)); } } else if (jsonContract is JsonPrimitiveContract) { CurrentSchema.Type = GetJsonSchemaType(type, valueRequired); if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum && !type.IsDefined(typeof(FlagsAttribute), inherit: true)) { CurrentSchema.Enum = new List <JToken>(); CurrentSchema.Options = new Dictionary <JToken, string>(); EnumValues <long> namesAndValues = EnumUtils.GetNamesAndValues <long>(type); foreach (EnumValue <long> item in namesAndValues) { JToken jToken = JToken.FromObject(item.Value); CurrentSchema.Enum.Add(jToken); CurrentSchema.Options.Add(jToken, item.Name); } } } else if (jsonContract is JsonObjectContract) { CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); CurrentSchema.Id = GetTypeId(type, explicitOnly: false); GenerateObjectSchema(type, (JsonObjectContract)jsonContract); } else if (jsonContract is JsonISerializableContract) { CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired); CurrentSchema.Id = GetTypeId(type, explicitOnly: false); GenerateISerializableContract(type, (JsonISerializableContract)jsonContract); } else if (jsonContract is JsonStringContract) { JsonSchemaType value = (!ReflectionUtils.IsNullable(jsonContract.UnderlyingType)) ? JsonSchemaType.String : AddNullType(JsonSchemaType.String, valueRequired); CurrentSchema.Type = value; } else { if (!(jsonContract is JsonLinqContract)) { throw new Exception("Unexpected contract type: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContract)); } CurrentSchema.Type = JsonSchemaType.Any; } return(Pop().Schema); }