private void LoadEnumerations(Type type, JsonSchema4 schema, JsonObjectTypeDescription typeDescription) { schema.Type = typeDescription.Type; schema.Enumeration.Clear(); schema.EnumerationNames.Clear(); foreach (var enumName in Enum.GetNames(type)) { if (typeDescription.Type == JsonObjectType.Integer) { var value = Convert.ChangeType(Enum.Parse(type, enumName), Enum.GetUnderlyingType(type)); schema.Enumeration.Add(value); } else { var attributes = type.GetTypeInfo().GetDeclaredField(enumName).GetCustomAttributes(); // EnumMember only checked if StringEnumConverter is used dynamic enumMemberAttribute = attributes.TryGetIfAssignableTo("System.Runtime.Serialization.EnumMemberAttribute"); if (enumMemberAttribute != null && !string.IsNullOrEmpty(enumMemberAttribute.Value)) { schema.Enumeration.Add((string)enumMemberAttribute.Value); } else { schema.Enumeration.Add(enumName); } } schema.EnumerationNames.Add(enumName); } }
private async Task AddKnownTypeAsync(Type type, JsonSchemaResolver schemaResolver) { var typeDescription = JsonObjectTypeDescription.FromType(type, ResolveContract(type), null, Settings.DefaultEnumHandling); var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(type, isIntegerEnum)) { await GenerateAsync(type, schemaResolver).ConfigureAwait(false); } }
private bool RequiresSchemaReference(Type type, IEnumerable <Attribute> parentAttributes) { var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); var typeMapper = Settings.TypeMappers.FirstOrDefault(m => m.MappedType == type); if (typeMapper != null) { return(typeMapper.UseReference); } return(!typeDescription.IsDictionary && (typeDescription.Type.HasFlag(JsonObjectType.Object) || typeDescription.IsEnum)); }
private void GenerateKnownTypes(Type type, JsonSchemaResolver schemaResolver) { foreach (dynamic knownTypeAttribute in type.GetTypeInfo().GetCustomAttributes().Where(a => a.GetType().Name == "KnownTypeAttribute")) { var typeDescription = JsonObjectTypeDescription.FromType(knownTypeAttribute.Type, null, Settings.DefaultEnumHandling); var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(knownTypeAttribute.Type, isIntegerEnum)) { Generate(knownTypeAttribute.Type, schemaResolver); } } }
private void GenerateKnownTypes(Type type, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { foreach (var knownTypeAttribute in type.GetTypeInfo().GetCustomAttributes <KnownTypeAttribute>()) { var typeDescription = JsonObjectTypeDescription.FromType(knownTypeAttribute.Type, null, Settings.DefaultEnumHandling); var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(knownTypeAttribute.Type, isIntegerEnum)) { var knownSchema = Generate(knownTypeAttribute.Type, rootSchema, null, schemaDefinitionAppender, schemaResolver); schemaDefinitionAppender.Append(rootSchema, knownSchema.ActualSchema); } } }
private object ConvertDefaultValue(Type parentType, IEnumerable <Attribute> propertyAttributes, dynamic defaultValueAttribute) { if (((Type)defaultValueAttribute.Value.GetType()).GetTypeInfo().IsEnum) { if (JsonObjectTypeDescription.IsStringEnum(parentType, propertyAttributes, Settings.DefaultEnumHandling)) { return(defaultValueAttribute.Value.ToString()); } else { return((int)defaultValueAttribute.Value); } } else { return(defaultValueAttribute.Value); } }
private string[] GetEnumNames(Type type, JsonObjectTypeDescription typeDescription) { if (typeDescription.Type == JsonObjectType.String) { return(Enum.GetNames(type).Select(name => { var attributes = type.GetTypeInfo().GetDeclaredField(name).GetCustomAttributes(); dynamic enumMemberAttribute = TryGetAttribute(attributes, "System.Runtime.Serialization.EnumMemberAttribute"); if (enumMemberAttribute != null && !string.IsNullOrEmpty(enumMemberAttribute.Value)) { return (string)enumMemberAttribute.Value; } return name; }).ToArray()); } return(Enum.GetNames(type)); }
private void LoadEnumerations(Type type, JsonSchema4 schema, JsonObjectTypeDescription typeDescription) { schema.Type = typeDescription.Type; schema.Enumeration.Clear(); schema.EnumerationNames.Clear(); foreach (var enumName in GetEnumNames(type, typeDescription)) { if (typeDescription.Type == JsonObjectType.Integer) { var value = Convert.ChangeType(Enum.Parse(type, enumName), Enum.GetUnderlyingType(type)); schema.Enumeration.Add(value); } else { schema.Enumeration.Add(enumName); } schema.EnumerationNames.Add(enumName); } }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schemaResolver"></param> /// <param name="schemaDefinitionAppender"></param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public virtual TSchemaType Generate <TSchemaType>(Type type, IEnumerable <Attribute> parentAttributes, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) where TSchemaType : JsonSchema4, new() { var schema = HandleSpecialTypes <TSchemaType>(type, schemaResolver); if (schema != null) { return(schema); } schema = new TSchemaType(); if (schemaDefinitionAppender.RootObject == null) { schemaDefinitionAppender.RootObject = schema; } ApplyExtensionDataAttributes(schema, type, parentAttributes); var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); if (typeDescription.Type.HasFlag(JsonObjectType.Object)) { if (typeDescription.IsDictionary) { typeDescription.ApplyType(schema); GenerateDictionary(type, schema, schemaResolver, schemaDefinitionAppender); } else { if (schemaResolver.HasSchema(type, false)) { schema.SchemaReference = schemaResolver.GetSchema(type, false); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { typeDescription.ApplyType(schema); schema.TypeNameRaw = ReflectionExtensions.GetSafeTypeName(type); schema.Description = GetDescription(type.GetTypeInfo(), type.GetTypeInfo().GetCustomAttributes()); GenerateObject(type, schema, schemaResolver, schemaDefinitionAppender); } else { schema.SchemaReference = Generate <JsonSchema4>(type, parentAttributes, schemaResolver, schemaDefinitionAppender); return(schema); } } } else if (type.GetTypeInfo().IsEnum) { var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) { schema.SchemaReference = schemaResolver.GetSchema(type, isIntegerEnumeration); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { LoadEnumerations(type, schema, typeDescription); typeDescription.ApplyType(schema); schema.TypeNameRaw = ReflectionExtensions.GetSafeTypeName(type); schema.Description = type.GetXmlSummary(); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { schema.SchemaReference = Generate <JsonSchema4>(type, parentAttributes, schemaResolver, schemaDefinitionAppender); return(schema); } } else if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { typeDescription.ApplyType(schema); var itemType = type.GetEnumerableItemType(); if (itemType == null) { var jsonSchemaAttribute = type.GetTypeInfo().GetCustomAttribute <JsonSchemaAttribute>(); if (jsonSchemaAttribute?.ArrayItem != null) { schema.Item = Generate(jsonSchemaAttribute.ArrayItem, schemaResolver, schemaDefinitionAppender); } else { schema.Item = JsonSchema4.CreateAnySchema(); } } else { if (itemType.GetTypeInfo().IsEnum) { schema.Item = new JsonSchema4 { SchemaReference = Generate(itemType, schemaResolver, schemaDefinitionAppender) } } ; else { schema.Item = Generate(itemType, schemaResolver, schemaDefinitionAppender); } } } else { typeDescription.ApplyType(schema); } return(schema); }
/// <summary>Applies the property annotations to the JSON property.</summary> /// <param name="jsonProperty">The JSON property.</param> /// <param name="parentType">The type of the parent.</param> /// <param name="attributes">The attributes.</param> /// <param name="propertyTypeDescription">The property type description.</param> public void ApplyPropertyAnnotations(JsonSchema4 jsonProperty, Type parentType, IList <Attribute> attributes, JsonObjectTypeDescription propertyTypeDescription) { // TODO: Refactor out dynamic displayAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DisplayAttribute"); if (displayAttribute != null && displayAttribute.Name != null) { jsonProperty.Title = displayAttribute.Name; } dynamic defaultValueAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DefaultValueAttribute"); if (defaultValueAttribute != null && defaultValueAttribute.Value != null) { jsonProperty.Default = ConvertDefaultValue(parentType, attributes, defaultValueAttribute); } dynamic regexAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RegularExpressionAttribute"); if (regexAttribute != null) { jsonProperty.Pattern = regexAttribute.Pattern; } if (propertyTypeDescription.Type == JsonObjectType.Number || propertyTypeDescription.Type == JsonObjectType.Integer) { dynamic rangeAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RangeAttribute"); if (rangeAttribute != null) { if (rangeAttribute.Minimum != null && rangeAttribute.Minimum > double.MinValue) { jsonProperty.Minimum = (decimal?)(double)rangeAttribute.Minimum; } if (rangeAttribute.Maximum != null && rangeAttribute.Maximum < double.MaxValue) { jsonProperty.Maximum = (decimal?)(double)rangeAttribute.Maximum; } } var multipleOfAttribute = attributes.OfType <MultipleOfAttribute>().SingleOrDefault(); if (multipleOfAttribute != null) { jsonProperty.MultipleOf = multipleOfAttribute.MultipleOf; } } dynamic minLengthAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MinLengthAttribute"); if (minLengthAttribute != null && minLengthAttribute.Length != null) { if (propertyTypeDescription.Type == JsonObjectType.String) { jsonProperty.MinLength = minLengthAttribute.Length; } else if (propertyTypeDescription.Type == JsonObjectType.Array) { jsonProperty.MinItems = minLengthAttribute.Length; } } dynamic maxLengthAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MaxLengthAttribute"); if (maxLengthAttribute != null && maxLengthAttribute.Length != null) { if (propertyTypeDescription.Type == JsonObjectType.String) { jsonProperty.MaxLength = maxLengthAttribute.Length; } else if (propertyTypeDescription.Type == JsonObjectType.Array) { jsonProperty.MaxItems = maxLengthAttribute.Length; } } dynamic stringLengthAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.StringLengthAttribute"); if (stringLengthAttribute != null) { if (propertyTypeDescription.Type == JsonObjectType.String) { jsonProperty.MinLength = stringLengthAttribute.MinimumLength; jsonProperty.MaxLength = stringLengthAttribute.MaximumLength; } } dynamic dataTypeAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DataTypeAttribute"); if (dataTypeAttribute != null) { var dataType = dataTypeAttribute.DataType.ToString(); if (DataTypeFormats.ContainsKey(dataType)) { jsonProperty.Format = DataTypeFormats[dataType]; } } }
private void LoadPropertyOrField(MemberInfo property, Type propertyType, Type parentType, JsonSchema4 parentSchema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var attributes = property.GetCustomAttributes(inherit: true).OfType <Attribute>().ToArray(); var propertyTypeDescription = JsonObjectTypeDescription.FromType(propertyType, attributes, Settings.DefaultEnumHandling); if (IsPropertyIgnored(parentType, attributes) == false) { JsonProperty jsonProperty; if (propertyType.Name == "Nullable`1") #if !LEGACY { propertyType = propertyType.GenericTypeArguments[0]; } #else { propertyType = propertyType.GetGenericArguments()[0]; } #endif var requiresSchemaReference = RequiresSchemaReference(propertyType, attributes); if (requiresSchemaReference) { var propertySchema = Generate <JsonSchema4>(propertyType, attributes, schemaResolver, schemaDefinitionAppender); // The schema is automatically added to Definitions if it is missing in JsonPathUtilities.GetJsonPath() if (Settings.NullHandling == NullHandling.JsonSchema) { jsonProperty = new JsonProperty(); jsonProperty.OneOf.Add(new JsonSchema4 { SchemaReference = propertySchema.ActualSchema }); } else { jsonProperty = new JsonProperty { SchemaReference = propertySchema.ActualSchema }; } } else { jsonProperty = Generate <JsonProperty>(propertyType, attributes, schemaResolver, schemaDefinitionAppender); } var propertyName = JsonPathUtilities.GetPropertyName(property, Settings.DefaultPropertyNameHandling); if (parentSchema.Properties.ContainsKey(propertyName)) { throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'."); } parentSchema.Properties.Add(propertyName, jsonProperty); var requiredAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RequiredAttribute"); var jsonPropertyAttribute = attributes.OfType <JsonPropertyAttribute>().SingleOrDefault(); var hasJsonNetAttributeRequired = jsonPropertyAttribute != null && ( jsonPropertyAttribute.Required == Required.Always || jsonPropertyAttribute.Required == Required.AllowNull); var isDataContractMemberRequired = GetDataMemberAttribute(parentType, attributes)?.IsRequired == true; var hasRequiredAttribute = requiredAttribute != null; if (hasRequiredAttribute || isDataContractMemberRequired || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); } var isJsonNetAttributeNullable = jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.AllowNull; var isNullable = !hasRequiredAttribute && !isDataContractMemberRequired && (propertyTypeDescription.IsNullable || isJsonNetAttributeNullable); if (isNullable) { if (Settings.NullHandling == NullHandling.JsonSchema) { if (requiresSchemaReference) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else if (jsonProperty.Type == JsonObjectType.None) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.None }); jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else { jsonProperty.Type = jsonProperty.Type | JsonObjectType.Null; } } } else if (Settings.NullHandling == NullHandling.Swagger) { if (!parentSchema.RequiredProperties.Contains(propertyName)) { parentSchema.RequiredProperties.Add(propertyName); } } dynamic readOnlyAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { jsonProperty.IsReadOnly = readOnlyAttribute.IsReadOnly; } jsonProperty.Description = GetDescription(property, attributes); ApplyPropertyAnnotations(jsonProperty, parentType, attributes, propertyTypeDescription); } }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="rootSchema">The root schema.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schemaDefinitionAppender">The schema definition appender.</param> /// <param name="schemaResolver">The schema resolver.</param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public TSchemaType Generate <TSchemaType>(Type type, JsonSchema4 rootSchema, IEnumerable <Attribute> parentAttributes, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new() { var schema = HandleSpecialTypes <TSchemaType>(type); if (schema != null) { return(schema); } schema = new TSchemaType(); if (rootSchema == null) { rootSchema = schema; } var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); typeDescription.ApplyType(schema); ApplyExtensionDataAttributes(schema, type, parentAttributes); if (schema.Type.HasFlag(JsonObjectType.Object)) { if (typeDescription.IsDictionary) { GenerateDictionary(type, rootSchema, schema, schemaDefinitionAppender, schemaResolver); } else { schema.TypeNameRaw = GetTypeName(type); if (schemaResolver.HasSchema(type, false)) { schema.SchemaReference = schemaResolver.GetSchema(type, false); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { schema.Description = GetDescription(type.GetTypeInfo(), type.GetTypeInfo().GetCustomAttributes()); GenerateObject(type, schema, rootSchema, schemaDefinitionAppender, schemaResolver); } else { schema.SchemaReference = Generate(type, rootSchema, parentAttributes, schemaDefinitionAppender, schemaResolver); return(schema); } } } else if (type.GetTypeInfo().IsEnum) { var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) { schema.Type = typeDescription.Type; schema.SchemaReference = schemaResolver.GetSchema(type, isIntegerEnumeration); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { LoadEnumerations(type, schema, typeDescription); schema.TypeNameRaw = GetTypeName(type); schema.Description = type.GetXmlDocumentation(); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { schema.SchemaReference = Generate(type, rootSchema, parentAttributes, schemaDefinitionAppender, schemaResolver); return(schema); } } else if (schema.Type.HasFlag(JsonObjectType.Array)) { schema.Type = JsonObjectType.Array; var genericTypeArguments = GetGenericTypeArguments(type); var itemType = genericTypeArguments.Length == 0 ? type.GetElementType() : genericTypeArguments[0]; if (itemType == null) { schema.Item = JsonSchema4.CreateAnySchema(); } else { schema.Item = Generate(itemType, rootSchema, null, schemaDefinitionAppender, schemaResolver); } } return(schema); }
/// <summary></summary> /// <param name="jsonProperty"></param> /// <param name="attributes"></param> /// <param name="propertyTypeDescription"></param> public void ApplyPropertyAnnotations(JsonSchema4 jsonProperty, IEnumerable <Attribute> attributes, JsonObjectTypeDescription propertyTypeDescription) { dynamic displayAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.DisplayAttribute"); if (displayAttribute != null && displayAttribute.Name != null) { jsonProperty.Title = displayAttribute.Name; } dynamic defaultValueAttribute = TryGetAttribute(attributes, "System.ComponentModel.DefaultValueAttribute"); if (defaultValueAttribute != null && defaultValueAttribute.Value != null) { jsonProperty.Default = defaultValueAttribute.Value; } dynamic regexAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.RegularExpressionAttribute"); if (regexAttribute != null) { jsonProperty.Pattern = regexAttribute.Pattern; } if (propertyTypeDescription.Type == JsonObjectType.Number || propertyTypeDescription.Type == JsonObjectType.Integer) { dynamic rangeAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.RangeAttribute"); if (rangeAttribute != null) { if (rangeAttribute.Minimum != null) { jsonProperty.Minimum = rangeAttribute.Minimum; } if (rangeAttribute.Maximum != null) { jsonProperty.Maximum = rangeAttribute.Maximum; } } var multipleOfAttribute = attributes.OfType <MultipleOfAttribute>().SingleOrDefault(); if (multipleOfAttribute != null) { jsonProperty.MultipleOf = multipleOfAttribute.MultipleOf; } } dynamic minLengthAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.MinLengthAttribute"); if (minLengthAttribute != null && minLengthAttribute.Length != null) { if (propertyTypeDescription.Type == JsonObjectType.String) { jsonProperty.MinLength = minLengthAttribute.Length; } else if (propertyTypeDescription.Type == JsonObjectType.Array) { jsonProperty.MinItems = minLengthAttribute.Length; } } dynamic maxLengthAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.MaxLengthAttribute"); if (maxLengthAttribute != null && maxLengthAttribute.Length != null) { if (propertyTypeDescription.Type == JsonObjectType.String) { jsonProperty.MaxLength = maxLengthAttribute.Length; } else if (propertyTypeDescription.Type == JsonObjectType.Array) { jsonProperty.MaxItems = maxLengthAttribute.Length; } } }
private void LoadProperty(Type parentType, PropertyInfo property, JsonSchema4 parentSchema, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { var propertyType = property.PropertyType; var propertyTypeDescription = JsonObjectTypeDescription.FromType(propertyType, property.GetCustomAttributes(), Settings.DefaultEnumHandling); var attributes = property.GetCustomAttributes().ToArray(); if (IsPropertyIgnored(parentType, attributes) == false) { JsonProperty jsonProperty; if (propertyType.Name == "Nullable`1") { propertyType = propertyType.GenericTypeArguments[0]; } var useSchemaReference = !propertyTypeDescription.IsDictionary && (propertyTypeDescription.Type.HasFlag(JsonObjectType.Object) || propertyTypeDescription.IsEnum); if (useSchemaReference) { // schema is automatically added to Definitions if it is missing in JsonPathUtilities.GetJsonPath() var propertySchema = Generate(propertyType, rootSchema, property.GetCustomAttributes(), schemaDefinitionAppender, schemaResolver); if (Settings.NullHandling == NullHandling.JsonSchema) { jsonProperty = new JsonProperty(); jsonProperty.OneOf.Add(new JsonSchema4 { SchemaReference = propertySchema.ActualSchema }); } else { jsonProperty = new JsonProperty { SchemaReference = propertySchema.ActualSchema }; } } else { jsonProperty = Generate <JsonProperty>(propertyType, rootSchema, property.GetCustomAttributes(), schemaDefinitionAppender, schemaResolver); propertyTypeDescription.ApplyType(jsonProperty); } var propertyName = JsonPathUtilities.GetPropertyName(property); parentSchema.Properties.Add(propertyName, jsonProperty); var requiredAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.RequiredAttribute"); var jsonPropertyAttribute = property.GetCustomAttribute <JsonPropertyAttribute>(); var hasJsonNetAttributeRequired = jsonPropertyAttribute != null && ( jsonPropertyAttribute.Required == Required.Always || jsonPropertyAttribute.Required == Required.AllowNull); var hasRequiredAttribute = requiredAttribute != null; if (hasRequiredAttribute || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); } var isJsonNetAttributeNullable = jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.AllowNull; var isNullable = !hasRequiredAttribute && (propertyTypeDescription.IsNullable || isJsonNetAttributeNullable); if (isNullable) { if (Settings.NullHandling == NullHandling.JsonSchema) { if (useSchemaReference) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else { jsonProperty.Type = jsonProperty.Type | JsonObjectType.Null; } } } else if (Settings.NullHandling == NullHandling.Swagger) { if (!parentSchema.RequiredProperties.Contains(propertyName)) { parentSchema.RequiredProperties.Add(propertyName); } } dynamic readOnlyAttribute = TryGetAttribute(attributes, "System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { jsonProperty.IsReadOnly = readOnlyAttribute.IsReadOnly; } jsonProperty.Description = GetDescription(property, attributes); ApplyPropertyAnnotations(jsonProperty, attributes, propertyTypeDescription); } }
private async Task LoadPropertyOrFieldAsync(Newtonsoft.Json.Serialization.JsonProperty property, MemberInfo propertyInfo, Type parentType, JsonSchema4 parentSchema, JsonSchemaResolver schemaResolver) { var propertyType = property.PropertyType; var attributes = property.AttributeProvider.GetAttributes(true).ToArray(); var propertyTypeDescription = JsonObjectTypeDescription.FromType(propertyType, ResolveContract(propertyType), null, Settings.DefaultEnumHandling); if (property.Ignored == false) { JsonProperty jsonProperty; if (propertyType.Name == "Nullable`1") #if !LEGACY { propertyType = propertyType.GenericTypeArguments[0]; } #else { propertyType = propertyType.GetGenericArguments()[0]; } #endif var requiresSchemaReference = RequiresSchemaReference(propertyType, attributes); if (requiresSchemaReference) { var propertySchema = await GenerateAsync(propertyType, attributes, schemaResolver).ConfigureAwait(false); // The schema is automatically added to Definitions if it is missing in JsonPathUtilities.GetJsonPath() if (Settings.NullHandling == NullHandling.JsonSchema) { jsonProperty = new JsonProperty(); jsonProperty.OneOf.Add(new JsonSchema4 { SchemaReference = propertySchema.ActualSchema }); } else { jsonProperty = new JsonProperty { SchemaReference = propertySchema.ActualSchema }; } } else { jsonProperty = await GenerateAsync <JsonProperty>(propertyType, attributes, schemaResolver).ConfigureAwait(false); } var contractResolver = Settings.ActualContractResolver as DefaultContractResolver; var propertyName = contractResolver != null? contractResolver.GetResolvedPropertyName(property.PropertyName) : property.PropertyName; if (parentSchema.Properties.ContainsKey(propertyName)) { throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'."); } if (Settings.GenerateXmlObjects) { jsonProperty.GenerateXmlObjectForProperty(parentType, propertyName, attributes); } parentSchema.Properties.Add(propertyName, jsonProperty); var requiredAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RequiredAttribute"); var hasJsonNetAttributeRequired = property.Required == Required.Always || property.Required == Required.AllowNull; var isDataContractMemberRequired = GetDataMemberAttribute(parentType, attributes)?.IsRequired == true; var hasRequiredAttribute = requiredAttribute != null; if (hasRequiredAttribute || isDataContractMemberRequired || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); } var isNullable = propertyTypeDescription.IsNullable && hasRequiredAttribute == false && isDataContractMemberRequired == false && (property.Required == Required.Default || property.Required == Required.AllowNull); if (isNullable) { if (Settings.NullHandling == NullHandling.JsonSchema) { if (requiresSchemaReference) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else if (jsonProperty.Type == JsonObjectType.None) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.None }); jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else { jsonProperty.Type = jsonProperty.Type | JsonObjectType.Null; } } } else if (Settings.NullHandling == NullHandling.Swagger) { if (!parentSchema.RequiredProperties.Contains(propertyName)) { parentSchema.RequiredProperties.Add(propertyName); } } dynamic readOnlyAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { jsonProperty.IsReadOnly = readOnlyAttribute.IsReadOnly; } jsonProperty.Description = await propertyInfo.GetDescriptionAsync(attributes).ConfigureAwait(false); ApplyPropertyAnnotations(jsonProperty, property, parentType, attributes, propertyTypeDescription); } }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <typeparam name="TSchemaType">The type of the schema.</typeparam> /// <param name="type">The type.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schema">The schema.</param> /// <param name="schemaResolver">The schema resolver.</param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public virtual async Task GenerateAsync <TSchemaType>(Type type, IEnumerable <Attribute> parentAttributes, TSchemaType schema, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new() { if (await TryHandleSpecialTypesAsync(type, schema, schemaResolver, parentAttributes)) { await ApplySchemaProcessorsAsync(schema, schemaResolver); return; } if (schemaResolver.RootObject == schema) { schema.Title = Settings.SchemaNameGenerator.Generate(type); } ApplyExtensionDataAttributes(type, schema, parentAttributes); var contract = ResolveContract(type); var typeDescription = JsonObjectTypeDescription.FromType(type, contract, parentAttributes, Settings.DefaultEnumHandling); if (typeDescription.Type.HasFlag(JsonObjectType.Object)) { if (typeDescription.IsDictionary) { typeDescription.ApplyType(schema); await GenerateDictionaryAsync(type, schema, schemaResolver).ConfigureAwait(false); } else { if (schemaResolver.HasSchema(type, false)) { schema.SchemaReference = schemaResolver.GetSchema(type, false); } else if (schema.GetType() == typeof(JsonSchema4)) { typeDescription.ApplyType(schema); schema.Description = await type.GetTypeInfo().GetDescriptionAsync(type.GetTypeInfo().GetCustomAttributes()).ConfigureAwait(false); await GenerateObjectAsync(type, contract, schema, schemaResolver).ConfigureAwait(false); } else { schema.SchemaReference = await GenerateAsync(type, parentAttributes, schemaResolver).ConfigureAwait(false); } } } else if (type.GetTypeInfo().IsEnum) { var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) { schema.SchemaReference = schemaResolver.GetSchema(type, isIntegerEnumeration); } else if (schema.GetType() == typeof(JsonSchema4)) { LoadEnumerations(type, schema, typeDescription); typeDescription.ApplyType(schema); schema.Description = await type.GetXmlSummaryAsync().ConfigureAwait(false); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { schema.SchemaReference = await GenerateAsync(type, parentAttributes, schemaResolver).ConfigureAwait(false); } } else if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { typeDescription.ApplyType(schema); var itemType = type.GetEnumerableItemType(); if (itemType != null) { schema.Item = await GenerateWithReferenceAsync(schemaResolver, itemType).ConfigureAwait(false); } else { schema.Item = JsonSchema4.CreateAnySchema(); } } else { typeDescription.ApplyType(schema); } await ApplySchemaProcessorsAsync(schema, schemaResolver); }