JsonSchemaGenerator
Generates a JsonSchema object for a given type.
using Namotion.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using NJsonSchema.Annotations;
using NJsonSchema.Converters;
using NJsonSchema.Generation.TypeMappers;
using NJsonSchema.Infrastructure;
using NJsonSchema.References;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NJsonSchema.Generation
{
public class JsonSchemaGenerator
{
private static readonly Dictionary<string, string> DataTypeFormats = new Dictionary<string, string> {
{
"DateTime",
"date-time"
},
{
"Date",
"date"
},
{
"Time",
"time"
},
{
"EmailAddress",
"email"
},
{
"PhoneNumber",
"phone"
},
{
"Url",
"uri"
}
};
public JsonSchemaGeneratorSettings Settings { get; }
public JsonSchemaGenerator(JsonSchemaGeneratorSettings settings)
{
Settings = settings;
}
public JsonSchema Generate(Type type)
{
JsonSchema jsonSchema = new JsonSchema();
JsonSchemaResolver schemaResolver = new JsonSchemaResolver(jsonSchema, Settings);
Generate(jsonSchema, type.ToContextualType(), schemaResolver);
return jsonSchema;
}
public JsonSchema Generate(Type type, JsonSchemaResolver schemaResolver)
{
return Generate<JsonSchema>(type, schemaResolver);
}
public TSchemaType Generate<TSchemaType>(Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
return Generate<TSchemaType>(type.ToContextualType(), schemaResolver);
}
public JsonSchema Generate(ContextualType contextualType, JsonSchemaResolver schemaResolver)
{
return Generate<JsonSchema>(contextualType, schemaResolver);
}
public TSchemaType Generate<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
TSchemaType val = new TSchemaType();
Generate(val, contextualType, schemaResolver);
return val;
}
public void Generate<TSchemaType>(TSchemaType schema, Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
Generate(schema, type.ToContextualType(), schemaResolver);
}
public virtual void Generate<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
Type type = contextualType.OriginalType;
JsonSchemaTypeAttribute attribute = contextualType.GetAttribute<JsonSchemaTypeAttribute>();
if (attribute != null)
type = attribute.Type;
ApplyExtensionDataAttributes(schema, contextualType);
if (TryHandleSpecialTypes(schema, contextualType, schemaResolver))
ApplySchemaProcessors(schema, contextualType, schemaResolver);
else {
if (schemaResolver.RootObject == schema)
schema.Title = Settings.SchemaNameGenerator.Generate(type);
JsonTypeDescription description = Settings.ReflectionService.GetDescription(contextualType, Settings);
if (description.Type.HasFlag(JsonObjectType.Object)) {
if (description.IsDictionary)
GenerateDictionary(schema, contextualType, description, schemaResolver);
else if (schemaResolver.HasSchema(type, false)) {
((JsonReferenceBase<JsonSchema>)schema).Reference = schemaResolver.GetSchema(type, false);
} else if (schema.GetType() == typeof(JsonSchema)) {
GenerateObject(schema, type, description, schemaResolver);
} else {
((JsonReferenceBase<JsonSchema>)schema).Reference = Generate(contextualType, schemaResolver);
}
} else if (description.IsEnum) {
GenerateEnum(schema, contextualType, description, schemaResolver);
} else if (description.Type.HasFlag(JsonObjectType.Array)) {
GenerateArray(schema, contextualType, description, schemaResolver);
} else {
description.ApplyType(schema);
}
ApplySchemaProcessors(schema, contextualType, schemaResolver);
}
}
public TSchemaType GenerateWithReference<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new
{
return GenerateWithReferenceAndNullability(contextualType, false, schemaResolver, transformation);
}
public TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new
{
JsonTypeDescription description = Settings.ReflectionService.GetDescription(contextualType, Settings);
return GenerateWithReferenceAndNullability(contextualType, description.IsNullable, schemaResolver, transformation);
}
public virtual TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(ContextualType contextualType, bool isNullable, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new
{
JsonSchema jsonSchema;
if (!Settings.ReflectionService.GetDescription(contextualType, Settings).RequiresSchemaReference(Settings.TypeMappers)) {
TSchemaType val = Generate<TSchemaType>(contextualType, schemaResolver);
if (!val.HasReference) {
transformation?.Invoke(val, (JsonSchema)val);
if (isNullable) {
if (Settings.SchemaType == SchemaType.JsonSchema) {
if (val.Type == JsonObjectType.None) {
val.OneOf.Add(new JsonSchema {
Type = JsonObjectType.None
});
val.OneOf.Add(new JsonSchema {
Type = JsonObjectType.Null
});
} else
val.Type |= JsonObjectType.Null;
} else if (Settings.SchemaType == SchemaType.OpenApi3 || Settings.GenerateCustomNullableProperties) {
val.IsNullableRaw = isNullable;
}
}
return val;
}
jsonSchema = val.ActualSchema;
} else
jsonSchema = Generate<JsonSchema>(contextualType, schemaResolver);
TSchemaType val2 = new TSchemaType();
transformation?.Invoke(val2, jsonSchema);
if (isNullable) {
if (Settings.SchemaType == SchemaType.JsonSchema)
val2.OneOf.Add(new JsonSchema {
Type = JsonObjectType.Null
});
else if (Settings.SchemaType == SchemaType.OpenApi3 || Settings.GenerateCustomNullableProperties) {
val2.IsNullableRaw = true;
}
}
if ((Settings.AllowReferencesWithProperties || !JsonConvert.DeserializeObject<JObject>(JsonConvert.SerializeObject(val2)).Properties().Any()) && val2.OneOf.Count == 0)
((JsonReferenceBase<JsonSchema>)val2).Reference = jsonSchema.ActualSchema;
else if (Settings.SchemaType != SchemaType.Swagger2) {
val2.OneOf.Add(new JsonSchema {
Reference = jsonSchema.ActualSchema
});
} else {
val2.AllOf.Add(new JsonSchema {
Reference = jsonSchema.ActualSchema
});
}
return val2;
}
public virtual string GetPropertyName(JsonProperty jsonProperty, ContextualMemberInfo contextualMember)
{
try {
string text = (contextualMember?.MemberInfo != (MemberInfo)null) ? contextualMember.MemberInfo.DeclaringType.GetContextualPropertiesAndFields().First((ContextualMemberInfo p) => p.Name == contextualMember.Name).GetName() : jsonProperty.PropertyName;
DefaultContractResolver defaultContractResolver = Settings.ActualContractResolver as DefaultContractResolver;
return (defaultContractResolver != null) ? defaultContractResolver.GetResolvedPropertyName(text) : text;
} catch (Exception innerException) {
throw new InvalidOperationException("Could not get JSON property name of property '" + ((contextualMember != null) ? contextualMember.Name : "n/a") + "' and type '" + ((contextualMember?.MemberInfo?.DeclaringType != (Type)null) ? contextualMember.MemberInfo.DeclaringType.FullName : "n/a") + "'.", innerException);
}
}
public virtual void ApplyDataAnnotations(JsonSchema schema, ContextualType contextualType, JsonTypeDescription typeDescription)
{
dynamic val = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DisplayAttribute", TypeNameStyle.FullName);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & (val.Name != null)))
schema.Title = (string)val.Name;
dynamic val3 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DefaultValueAttribute", TypeNameStyle.FullName);
if (val3 != null) {
if (typeDescription.IsEnum && typeDescription.Type.HasFlag(JsonObjectType.String))
schema.Default = (object)val3.Value?.ToString();
else
schema.Default = (object)val3.Value;
}
dynamic val4 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RegularExpressionAttribute", TypeNameStyle.FullName);
if (val4 != null) {
if (typeDescription.IsDictionary)
schema.AdditionalPropertiesSchema.Pattern = (string)val4.Pattern;
else
schema.Pattern = (string)val4.Pattern;
}
if (typeDescription.Type == JsonObjectType.Number || typeDescription.Type == JsonObjectType.Integer) {
ApplyRangeAttribute(schema, contextualType.ContextAttributes);
MultipleOfAttribute multipleOfAttribute = contextualType.ContextAttributes.OfType<MultipleOfAttribute>().SingleOrDefault();
if (multipleOfAttribute != null)
schema.MultipleOf = multipleOfAttribute.MultipleOf;
}
dynamic val5 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MinLengthAttribute", TypeNameStyle.FullName);
val2 = (val5 != null);
if ((val2 ? false : true) ? val2 : (val2 & (val5.Length != null))) {
if (typeDescription.Type == JsonObjectType.String)
schema.MinLength = (int?)val5.Length;
else if (typeDescription.Type == JsonObjectType.Array) {
schema.MinItems = (int)val5.Length;
}
}
dynamic val6 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MaxLengthAttribute", TypeNameStyle.FullName);
val2 = (val6 != null);
if ((val2 ? false : true) ? val2 : (val2 & (val6.Length != null))) {
if (typeDescription.Type == JsonObjectType.String)
schema.MaxLength = (int?)val6.Length;
else if (typeDescription.Type == JsonObjectType.Array) {
schema.MaxItems = (int)val6.Length;
}
}
dynamic val7 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.StringLengthAttribute", TypeNameStyle.FullName);
if ((val7 != null) && typeDescription.Type == JsonObjectType.String) {
schema.MinLength = (int?)val7.MinimumLength;
schema.MaxLength = (int?)val7.MaximumLength;
}
dynamic val8 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DataTypeAttribute", TypeNameStyle.FullName);
if (val8 != null) {
dynamic val9 = val8.DataType.ToString();
if (DataTypeFormats.ContainsKey(val9))
schema.Format = (string)DataTypeFormats[val9];
}
}
public virtual object ConvertDefaultValue(ContextualType type, object defaultValue)
{
if (defaultValue != null && LegacyTypeExtensions.GetTypeInfo(defaultValue.GetType()).IsEnum) {
if (Settings.ReflectionService.IsStringEnum(type, Settings.ActualSerializerSettings))
return defaultValue.ToString();
return (int)defaultValue;
}
return defaultValue;
}
protected virtual void GenerateObject(JsonSchema schema, Type type, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
{
schemaResolver.AddSchema(type, false, schema);
JsonSchema schema2 = schema;
JsonSchema jsonSchema = GenerateInheritance(type, schema, schemaResolver);
if (jsonSchema != null)
schema = jsonSchema;
else {
GenerateProperties(type, schema, schemaResolver);
ApplyAdditionalProperties(schema, type, schemaResolver);
}
if (!schema.Type.HasFlag(JsonObjectType.Array))
typeDescription.ApplyType(schema);
schema.Description = type.ToCachedType().GetDescription(DescriptionAttributeType.Context);
if (Settings.GetActualGenerateAbstractSchema(type))
schema.IsAbstract = LegacyTypeExtensions.GetTypeInfo(type).IsAbstract;
GenerateInheritanceDiscriminator(type, schema2, schema);
GenerateKnownTypes(type, schemaResolver);
if (Settings.GenerateXmlObjects)
schema.GenerateXmlObjectForType(type);
}
protected virtual string[] GetTypeProperties(Type type)
{
if (type == typeof(Exception))
return new string[4] {
"InnerException",
"Message",
"Source",
"StackTrace"
};
return null;
}
protected virtual void GenerateArray<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
typeDescription.ApplyType(schema);
Type type = contextualType.GetTypeAttribute<JsonSchemaAttribute>()?.ArrayItem ?? contextualType.OriginalType.GetEnumerableItemType();
if (type != (Type)null) {
ContextualType contextualItemType = type.ToContextualType();
bool isNullable = contextualType.GetContextAttribute<ItemsCanBeNullAttribute>() != null || contextualItemType.Nullability == Nullability.Nullable;
schema.Item = GenerateWithReferenceAndNullability(contextualItemType, isNullable, schemaResolver, delegate(JsonSchema itemSchema, JsonSchema typeSchema) {
if (Settings.GenerateXmlObjects)
itemSchema.GenerateXmlObjectForItemType(contextualItemType);
});
if (Settings.GenerateXmlObjects)
schema.GenerateXmlObjectForArrayType();
} else
schema.Item = JsonSchema.CreateAnySchema();
dynamic val = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val, "Length")))
schema.MinItems = (int)val.Length;
dynamic val3 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name);
val2 = (val3 != null);
if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val3, "Length")))
schema.MaxItems = (int)val3.Length;
}
protected virtual void GenerateDictionary<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
typeDescription.ApplyType(schema);
ContextualType[] genericArguments = contextualType.GenericArguments;
ContextualType contextualType2 = (genericArguments.Length == 2) ? genericArguments[0] : typeof(string).ToContextualType();
if (LegacyTypeExtensions.GetTypeInfo(contextualType2.OriginalType).IsEnum)
schema.DictionaryKey = GenerateWithReference<JsonSchema>(contextualType2, schemaResolver, null);
ContextualType contextualType3 = (genericArguments.Length == 2) ? genericArguments[1] : typeof(object).ToContextualType();
IEnumerable<JsonSchemaPatternPropertiesAttribute> enumerable = contextualType.ContextAttributes.OfType<JsonSchemaPatternPropertiesAttribute>();
if (enumerable.Any()) {
schema.AllowAdditionalProperties = false;
foreach (JsonSchemaPatternPropertiesAttribute item in enumerable) {
Type type = item.Type;
JsonSchemaProperty value = GenerateDictionaryValueSchema<JsonSchemaProperty>(schemaResolver, (((object)type != null) ? type.ToContextualType() : null) ?? contextualType3);
schema.PatternProperties.Add(item.RegularExpression, value);
}
} else {
schema.AdditionalPropertiesSchema = GenerateDictionaryValueSchema<JsonSchema>(schemaResolver, contextualType3);
schema.AllowAdditionalProperties = true;
}
dynamic val = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val, "Length")))
schema.MinProperties = (int)val.Length;
dynamic val3 = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name);
val2 = (val3 != null);
if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val3, "Length")))
schema.MaxProperties = (int)val3.Length;
}
protected virtual void GenerateEnum(JsonSchema schema, CachedType type, JsonTypeDescription typeDescription)
{
schema.Type = typeDescription.Type;
schema.Enumeration.Clear();
schema.EnumerationNames.Clear();
schema.IsFlagEnumerable = (type.GetTypeAttribute<FlagsAttribute>() != null);
Type underlyingType = Enum.GetUnderlyingType(type);
List<JsonConverter> list = Settings.ActualSerializerSettings.Converters.ToList();
if (!list.OfType<StringEnumConverter>().Any())
list.Add(new StringEnumConverter());
string[] names = Enum.GetNames(type);
foreach (string text in names) {
if (typeDescription.Type == JsonObjectType.Integer) {
object item = Convert.ChangeType(Enum.Parse(type, text), underlyingType);
schema.Enumeration.Add(item);
} else {
dynamic val = LegacyTypeExtensions.GetCustomAttributes(type.TypeInfo.GetDeclaredField(text), true).FirstAssignableToTypeNameOrDefault("System.Runtime.Serialization.EnumMemberAttribute", TypeNameStyle.FullName);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & !string.IsNullOrEmpty(val.Value)))
schema.Enumeration.Add((string)val.Value);
else {
string value = JsonConvert.SerializeObject(Enum.Parse(type, text), Formatting.None, list.ToArray());
schema.Enumeration.Add(JsonConvert.DeserializeObject<string>(value));
}
}
schema.EnumerationNames.Add(text);
}
if (typeDescription.Type == JsonObjectType.Integer && Settings.GenerateEnumMappingDescription)
schema.Description = (schema.Description + "\n\n" + string.Join("\n", schema.Enumeration.Select((object e, int i) => e + " = " + schema.EnumerationNames[i]))).Trim();
}
private TSchema GenerateDictionaryValueSchema<TSchema>(JsonSchemaResolver schemaResolver, ContextualType valueType) where TSchema : JsonSchema, new
{
if (valueType.OriginalType == typeof(object)) {
TSchema val = new TSchema();
if (Settings.SchemaType == SchemaType.Swagger2)
val.AllowAdditionalProperties = false;
return val;
}
JsonTypeDescription description = Settings.ReflectionService.GetDescription(valueType, Settings.DefaultDictionaryValueReferenceTypeNullHandling, Settings);
bool isNullable = valueType.GetContextAttribute<ItemsCanBeNullAttribute>() != null || description.IsNullable;
return GenerateWithReferenceAndNullability<TSchema>(valueType, isNullable, schemaResolver, null);
}
private void ApplyAdditionalProperties<TSchemaType>(TSchemaType schema, Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
ContextualPropertyInfo contextualPropertyInfo = type.GetContextualProperties().FirstOrDefault((ContextualPropertyInfo p) => ((ContextualType)p).GetContextAttribute<JsonExtensionDataAttribute>() != null);
if (contextualPropertyInfo != null) {
ContextualType[] genericArguments = contextualPropertyInfo.GenericArguments;
ContextualType contextualType = (genericArguments.Length == 2) ? genericArguments[1] : typeof(object).ToContextualType();
schema.AdditionalPropertiesSchema = GenerateWithReferenceAndNullability<JsonSchema>(contextualType, schemaResolver, null);
} else
schema.AllowAdditionalProperties = Settings.AlwaysAllowAdditionalObjectProperties;
}
private void ApplySchemaProcessors(JsonSchema schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
{
SchemaProcessorContext schemaProcessorContext = new SchemaProcessorContext(contextualType.OriginalType, schema, schemaResolver, this, Settings);
foreach (ISchemaProcessor schemaProcessor in Settings.SchemaProcessors) {
schemaProcessor.Process(schemaProcessorContext);
}
foreach (dynamic item in contextualType.TypeAttributes.GetAssignableToTypeName("JsonSchemaProcessorAttribute", TypeNameStyle.Name)) {
dynamic val = Activator.CreateInstance(item.Type, item.Parameters);
val.Process(schemaProcessorContext);
}
}
private void ApplyExtensionDataAttributes<TSchemaType>(TSchemaType schema, ContextualType contextualType) where TSchemaType : JsonSchema, new
{
JsonSchemaExtensionDataAttribute[] source = contextualType.GetAttributes<JsonSchemaExtensionDataAttribute>().ToArray();
if (source.Any())
schema.ExtensionData = source.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value);
else {
source = contextualType.GetAttributes<JsonSchemaExtensionDataAttribute>().ToArray();
if (source.Any())
schema.ExtensionData = source.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value);
}
}
private bool TryHandleSpecialTypes<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
ITypeMapper typeMapper = Settings.TypeMappers.FirstOrDefault((ITypeMapper m) => m.MappedType == contextualType.OriginalType);
if (typeMapper == null && LegacyTypeExtensions.GetTypeInfo(contextualType.OriginalType).IsGenericType) {
Type genericType = contextualType.OriginalType.GetGenericTypeDefinition();
typeMapper = Settings.TypeMappers.FirstOrDefault((ITypeMapper m) => m.MappedType == genericType);
}
if (typeMapper != null) {
TypeMapperContext context = new TypeMapperContext(contextualType.OriginalType, this, schemaResolver, contextualType.ContextAttributes);
typeMapper.GenerateSchema(schema, context);
return true;
}
if (!contextualType.OriginalType.IsAssignableToTypeName("JArray", TypeNameStyle.Name) && (contextualType.OriginalType.IsAssignableToTypeName("JToken", TypeNameStyle.Name) || contextualType.OriginalType == typeof(object))) {
if (Settings.SchemaType == SchemaType.Swagger2)
schema.AllowAdditionalProperties = false;
return true;
}
return false;
}
private void GenerateEnum<TSchemaType>(TSchemaType schema, CachedType contextualType, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new
{
Type type = contextualType.Type;
bool isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer;
if (schemaResolver.HasSchema(type, isIntegerEnumeration))
((JsonReferenceBase<JsonSchema>)schema).Reference = schemaResolver.GetSchema(type, isIntegerEnumeration);
else if (schema.GetType() == typeof(JsonSchema)) {
typeDescription.ApplyType(schema);
schema.Description = type.GetXmlDocsSummary();
GenerateEnum(schema, type.ToCachedType(), typeDescription);
schemaResolver.AddSchema(type, isIntegerEnumeration, schema);
} else {
((JsonReferenceBase<JsonSchema>)schema).Reference = Generate(contextualType, schemaResolver);
}
}
private void GenerateProperties(Type type, JsonSchema schema, JsonSchemaResolver schemaResolver)
{
IEnumerable<ContextualMemberInfo> source = from m in LegacyTypeExtensions.GetTypeInfo(type).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).Where(delegate(FieldInfo f) {
if (f.IsPublic)
return !f.IsStatic;
return false;
})
.OfType<MemberInfo>()
.Concat(LegacyTypeExtensions.GetTypeInfo(type).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).Where(delegate(PropertyInfo p) {
if (p.GetGetMethod()?.IsPublic ?? false) {
MethodInfo getMethod2 = p.GetGetMethod();
if ((object)getMethod2 != null && !getMethod2.IsStatic)
return true;
}
if (p.GetSetMethod()?.IsPublic ?? false) {
MethodInfo setMethod2 = p.GetSetMethod();
if ((object)setMethod2 == null)
return false;
return !setMethod2.IsStatic;
}
return false;
}))
.ToList()
select m.ToContextualMember();
JsonContract jsonContract = Settings.ResolveContract(type);
string[] allowedProperties = GetTypeProperties(type);
JsonObjectContract jsonObjectContract = jsonContract as JsonObjectContract;
if (jsonObjectContract != null && allowedProperties == null) {
foreach (JsonProperty item in from p in jsonObjectContract.Properties
where p.DeclaringType == type
select p) {
bool flag;
try {
flag = (item.ShouldSerialize?.Invoke(null) ?? true);
} catch {
flag = true;
}
if (flag) {
ContextualMemberInfo contextualMemberInfo = source.FirstOrDefault((ContextualMemberInfo p) => p.Name == item.UnderlyingName);
ContextualPropertyInfo contextualPropertyInfo = contextualMemberInfo as ContextualPropertyInfo;
if (!Settings.GenerateAbstractProperties && contextualPropertyInfo != null && !LegacyTypeExtensions.GetTypeInfo(contextualPropertyInfo.PropertyInfo.DeclaringType).IsInterface) {
MethodInfo getMethod = contextualPropertyInfo.PropertyInfo.GetGetMethod();
if ((object)getMethod != null && getMethod.IsAbstract)
continue;
MethodInfo setMethod = contextualPropertyInfo.PropertyInfo.GetSetMethod();
if ((object)setMethod != null && setMethod.IsAbstract)
continue;
}
LoadPropertyOrField(item, contextualMemberInfo, type, schema, schemaResolver);
}
}
} else {
foreach (ContextualMemberInfo item2 in source.Where(delegate(ContextualMemberInfo m) {
if (allowedProperties != null)
return allowedProperties.Contains(m.Name);
return true;
})) {
JsonPropertyAttribute contextAttribute = item2.GetContextAttribute<JsonPropertyAttribute>();
Type propertyType = (item2 as ContextualPropertyInfo)?.PropertyInfo.PropertyType ?? (item2 as ContextualFieldInfo)?.FieldInfo.FieldType;
JsonProperty jsonProperty2 = new JsonProperty {
AttributeProvider = new ReflectionAttributeProvider(item2),
PropertyType = propertyType,
Ignored = IsPropertyIgnored(item2, type)
};
if (contextAttribute != null) {
jsonProperty2.PropertyName = (contextAttribute.PropertyName ?? item2.Name);
jsonProperty2.Required = contextAttribute.Required;
jsonProperty2.DefaultValueHandling = contextAttribute.DefaultValueHandling;
jsonProperty2.TypeNameHandling = contextAttribute.TypeNameHandling;
jsonProperty2.NullValueHandling = contextAttribute.NullValueHandling;
jsonProperty2.TypeNameHandling = contextAttribute.TypeNameHandling;
} else
jsonProperty2.PropertyName = item2.Name;
LoadPropertyOrField(jsonProperty2, item2, type, schema, schemaResolver);
}
}
}
private void GenerateKnownTypes(Type type, JsonSchemaResolver schemaResolver)
{
object[] customAttributes = LegacyTypeExtensions.GetTypeInfo(type).GetCustomAttributes(Settings.GetActualFlattenInheritanceHierarchy(type));
if (Settings.GenerateKnownTypes) {
foreach (dynamic item in customAttributes.GetAssignableToTypeName("KnownTypeAttribute", TypeNameStyle.Name).OfType<Attribute>()) {
if (item.Type != null)
this.AddKnownType(item.Type, schemaResolver);
else {
if (!((item.MethodName != null) ? true : false))
throw new ArgumentException("A KnownType attribute on " + type.FullName + " does not specify a type or a method name.", "type");
MethodInfo runtimeMethod = LegacyTypeExtensions.GetRuntimeMethod(type, (string)item.MethodName, new Type[0]);
if (runtimeMethod != (MethodInfo)null) {
IEnumerable<Type> enumerable = runtimeMethod.Invoke(null, null) as IEnumerable<Type>;
if (enumerable != null) {
foreach (Type item2 in enumerable) {
AddKnownType(item2, schemaResolver);
}
}
}
}
}
}
foreach (object item3 in customAttributes.GetAssignableToTypeName("JsonInheritanceAttribute", TypeNameStyle.Name)) {
Type type2 = item3.TryGetPropertyValue<Type>("Type", null);
if (type2 != (Type)null)
AddKnownType(type2, schemaResolver);
}
}
private void AddKnownType(Type type, JsonSchemaResolver schemaResolver)
{
bool isIntegerEnumeration = Settings.ReflectionService.GetDescription(type.ToContextualType(), Settings).Type == JsonObjectType.Integer;
if (!schemaResolver.HasSchema(type, isIntegerEnumeration))
Generate(type, schemaResolver);
}
private JsonSchema GenerateInheritance(Type type, JsonSchema schema, JsonSchemaResolver schemaResolver)
{
Type baseType = LegacyTypeExtensions.GetTypeInfo(type).BaseType;
if (baseType != (Type)null && baseType != typeof(object) && baseType != typeof(ValueType) && LegacyTypeExtensions.GetTypeInfo(baseType).GetCustomAttributes(false).FirstAssignableToTypeNameOrDefault("JsonSchemaIgnoreAttribute", TypeNameStyle.Name) == null && LegacyTypeExtensions.GetTypeInfo(baseType).GetCustomAttributes(false).FirstAssignableToTypeNameOrDefault("SwaggerIgnoreAttribute", TypeNameStyle.Name) == null) {
string[] excludedTypeNames = Settings.ExcludedTypeNames;
if (excludedTypeNames == null || !excludedTypeNames.Contains(baseType.FullName)) {
if (!Settings.GetActualFlattenInheritanceHierarchy(type)) {
JsonSchema jsonSchema = new JsonSchema();
GenerateProperties(type, jsonSchema, schemaResolver);
ApplyAdditionalProperties(jsonSchema, type, schemaResolver);
bool flag = Settings.ReflectionService.GetDescription(baseType.ToContextualType(), Settings).RequiresSchemaReference(Settings.TypeMappers);
if (jsonSchema.Properties.Any() | flag) {
JsonSchema jsonSchema2 = Generate(baseType, schemaResolver);
if (flag) {
if (schemaResolver.RootObject != jsonSchema2.ActualSchema)
schemaResolver.AppendSchema(jsonSchema2.ActualSchema, Settings.SchemaNameGenerator.Generate(baseType));
schema.AllOf.Add(new JsonSchema {
Reference = jsonSchema2.ActualSchema
});
} else
schema.AllOf.Add(jsonSchema2);
schema.AllOf.Add(jsonSchema);
return jsonSchema;
}
Generate(schema, baseType.ToContextualType(), schemaResolver);
return schema;
}
if (!Settings.ReflectionService.GetDescription(baseType.ToContextualType(), Settings).IsDictionary && !type.IsArray) {
GenerateProperties(baseType, schema, schemaResolver);
JsonSchema jsonSchema3 = GenerateInheritance(baseType, schema, schemaResolver);
GenerateInheritanceDiscriminator(baseType, schema, jsonSchema3 ?? schema);
}
}
}
if (Settings.GetActualFlattenInheritanceHierarchy(type) && Settings.GenerateAbstractProperties) {
Type[] interfaces = LegacyTypeExtensions.GetTypeInfo(type).GetInterfaces();
foreach (Type type2 in interfaces) {
if (!Settings.ReflectionService.GetDescription(type2.ToContextualType(), Settings).IsDictionary && !type.IsArray && !LegacyTypeExtensions.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(LegacyTypeExtensions.GetTypeInfo(type2))) {
GenerateProperties(type2, schema, schemaResolver);
JsonSchema jsonSchema4 = GenerateInheritance(type2, schema, schemaResolver);
GenerateInheritanceDiscriminator(type2, schema, jsonSchema4 ?? schema);
}
}
}
return null;
}
private void GenerateInheritanceDiscriminator(Type type, JsonSchema schema, JsonSchema typeSchema)
{
if (!Settings.GetActualFlattenInheritanceHierarchy(type)) {
object obj = TryGetInheritanceDiscriminatorConverter(type);
if (obj != null) {
string text = TryGetInheritanceDiscriminatorName(obj);
if (typeSchema.Properties.TryGetValue(text, out JsonSchemaProperty value) && (value.Type & JsonObjectType.String) == JsonObjectType.None)
throw new InvalidOperationException("The JSON discriminator property '" + text + "' must be a string property on type '" + type.FullName + "' (it is recommended to not implement the discriminator property at all).");
OpenApiDiscriminator openApiDiscriminator2 = typeSchema.DiscriminatorObject = new OpenApiDiscriminator {
JsonInheritanceConverter = obj,
PropertyName = text
};
typeSchema.Properties[text] = new JsonSchemaProperty {
Type = JsonObjectType.String,
IsRequired = true
};
} else
(schema.ResponsibleDiscriminatorObject ?? schema.ActualTypeSchema.ResponsibleDiscriminatorObject)?.AddMapping(type, schema);
}
}
private object TryGetInheritanceDiscriminatorConverter(Type type)
{
dynamic val = LegacyTypeExtensions.GetTypeInfo(type).GetCustomAttributes(false).OfType<Attribute>()
.FirstAssignableToTypeNameOrDefault("JsonConverterAttribute", TypeNameStyle.Name);
if ((val != null) && ((Type)val.ConverterType).IsAssignableToTypeName("JsonInheritanceConverter", TypeNameStyle.Name)) {
dynamic val2 = val.ConverterParameters != null;
if (!(((val2 ? false : true) ? val2 : (val2 & (val.ConverterParameters.Length > 0))) ? true : false))
return Activator.CreateInstance(val.ConverterType);
return Activator.CreateInstance(val.ConverterType, val.ConverterParameters);
}
return null;
}
private string TryGetInheritanceDiscriminatorName(dynamic jsonInheritanceConverter)
{
if (ObjectExtensions.HasProperty(jsonInheritanceConverter, "DiscriminatorName"))
return (string)jsonInheritanceConverter.DiscriminatorName;
return JsonInheritanceConverter.DefaultDiscriminatorName;
}
private void LoadPropertyOrField(JsonProperty jsonProperty, ContextualMemberInfo memberInfo, Type parentType, JsonSchema parentSchema, JsonSchemaResolver schemaResolver)
{
JsonTypeDescription propertyTypeDescription = Settings.ReflectionService.GetDescription(memberInfo, Settings);
if (!jsonProperty.Ignored && !IsPropertyIgnoredBySettings(memberInfo)) {
string propertyName = GetPropertyName(jsonProperty, memberInfo);
if (parentSchema.Properties.ContainsKey(propertyName)) {
if (!Settings.GetActualFlattenInheritanceHierarchy(parentType))
throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'.");
parentSchema.Properties.Remove(propertyName);
}
Attribute requiredAttribute = memberInfo.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RequiredAttribute", TypeNameStyle.FullName);
bool flag = jsonProperty.Required == Required.Always || jsonProperty.Required == Required.AllowNull;
dynamic val = GetDataMemberAttribute(memberInfo, parentType)?.IsRequired == true;
bool hasRequiredAttribute = requiredAttribute != null;
dynamic val2 = hasRequiredAttribute ? ((object)hasRequiredAttribute) : (hasRequiredAttribute | val);
if ((val2) || ((val2 | flag) ? true : false))
parentSchema.RequiredProperties.Add(propertyName);
bool isNullable = propertyTypeDescription.IsNullable && !hasRequiredAttribute && (jsonProperty.Required == Required.Default || jsonProperty.Required == Required.AllowNull);
Action<JsonSchemaProperty, JsonSchema> transformation = delegate(JsonSchemaProperty propertySchema, JsonSchema typeSchema) {
if (Settings.GenerateXmlObjects)
propertySchema.GenerateXmlObjectForProperty(memberInfo, propertyName);
if (hasRequiredAttribute && propertyTypeDescription.Type == JsonObjectType.String && !requiredAttribute.TryGetPropertyValue("AllowEmptyStrings", false))
propertySchema.MinLength = 1;
if (!isNullable && Settings.SchemaType == SchemaType.Swagger2 && !parentSchema.RequiredProperties.Contains(propertyName))
parentSchema.RequiredProperties.Add(propertyName);
object obj = memberInfo.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.ReadOnlyAttribute", TypeNameStyle.FullName);
if ((dynamic)obj != null)
propertySchema.IsReadOnly = ((byte)((dynamic)obj).IsReadOnly != 0);
if (propertySchema.Description == null)
propertySchema.Description = memberInfo.GetDescription(DescriptionAttributeType.Context);
propertySchema.Default = ConvertDefaultValue(memberInfo, jsonProperty.DefaultValue);
ApplyDataAnnotations(propertySchema, memberInfo, propertyTypeDescription);
};
JsonSchemaProperty value = GenerateWithReferenceAndNullability(memberInfo, isNullable, schemaResolver, transformation);
parentSchema.Properties.Add(propertyName, value);
}
}
private bool IsPropertyIgnored(ContextualMemberInfo property, Type parentType)
{
if (property.GetContextAttribute<JsonIgnoreAttribute>() != null)
return true;
bool flag = property.GetContextAttribute<JsonPropertyAttribute>() == null && HasDataContractAttribute(parentType);
if ((!flag) ? ((object)flag) : (flag & (GetDataMemberAttribute(property, parentType) == null)))
return true;
return IsPropertyIgnoredBySettings(property);
}
private bool IsPropertyIgnoredBySettings(ContextualMemberInfo property)
{
if (Settings.IgnoreObsoleteProperties && property.GetContextAttribute<ObsoleteAttribute>() != null)
return true;
return false;
}
private dynamic GetDataMemberAttribute(ContextualMemberInfo property, Type parentType)
{
if (!HasDataContractAttribute(parentType))
return null;
return property.ContextAttributes.FirstAssignableToTypeNameOrDefault("DataMemberAttribute", TypeNameStyle.Name);
}
private bool HasDataContractAttribute(Type parentType)
{
return parentType.ToCachedType().TypeAttributes.FirstAssignableToTypeNameOrDefault("DataContractAttribute", TypeNameStyle.Name) != null;
}
private void ApplyRangeAttribute(JsonSchema schema, IEnumerable<Attribute> parentAttributes)
{
dynamic val = parentAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RangeAttribute", TypeNameStyle.FullName);
if (val != null) {
if (val.Minimum != null) {
if (val.OperandType == typeof(double)) {
double num = (double)Convert.ChangeType(val.Minimum, typeof(double));
if (num > -1.7976931348623157E+308)
schema.Minimum = (decimal)num;
} else {
decimal num2 = (decimal)Convert.ChangeType(val.Minimum, typeof(decimal));
if (num2 > decimal.MinValue)
schema.Minimum = num2;
}
}
if (val.Maximum != null) {
if (val.OperandType == typeof(double)) {
double num3 = (double)Convert.ChangeType(val.Maximum, typeof(double));
if (num3 < 1.7976931348623157E+308)
schema.Maximum = (decimal)num3;
} else {
decimal num4 = (decimal)Convert.ChangeType(val.Maximum, typeof(decimal));
if (num4 < decimal.MaxValue)
schema.Maximum = num4;
}
}
}
}
}
}