DefaultReflectionService
The default reflection service implementation.
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using NJsonSchema.Annotations;
using NJsonSchema.Infrastructure;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NJsonSchema.Generation
{
public class DefaultReflectionService : IReflectionService
{
public virtual JsonTypeDescription GetDescription(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaGeneratorSettings settings)
{
bool isNullable = IsNullable(type, parentAttributes, settings);
JsonSchemaTypeAttribute jsonSchemaTypeAttribute = type.GetTypeInfo().GetCustomAttribute<JsonSchemaTypeAttribute>() ?? ((parentAttributes != null) ? parentAttributes.OfType<JsonSchemaTypeAttribute>().SingleOrDefault() : null);
if (jsonSchemaTypeAttribute != null) {
type = jsonSchemaTypeAttribute.Type;
if (jsonSchemaTypeAttribute.IsNullableRaw.HasValue)
isNullable = jsonSchemaTypeAttribute.IsNullableRaw.Value;
}
JsonSchemaAttribute jsonSchemaAttribute = type.GetTypeInfo().GetCustomAttribute<JsonSchemaAttribute>() ?? ((parentAttributes != null) ? parentAttributes.OfType<JsonSchemaAttribute>().SingleOrDefault() : null);
if (jsonSchemaAttribute != null) {
JsonObjectType jsonType = (jsonSchemaAttribute.Type != 0) ? jsonSchemaAttribute.Type : JsonObjectType.Object;
string format = (!string.IsNullOrEmpty(jsonSchemaAttribute.Format)) ? jsonSchemaAttribute.Format : null;
return JsonTypeDescription.Create(type, jsonType, isNullable, format);
}
if (type.GetTypeInfo().get_IsEnum()) {
bool flag = IsStringEnum(type, parentAttributes, settings);
return JsonTypeDescription.CreateForEnumeration(type, flag ? JsonObjectType.String : JsonObjectType.Integer, false);
}
if ((object)type == typeof(short) || (object)type == typeof(uint) || (object)type == typeof(ushort))
return JsonTypeDescription.Create(type, JsonObjectType.Integer, false, null);
if ((object)type == typeof(int))
return JsonTypeDescription.Create(type, JsonObjectType.Integer, false, "int32");
if ((object)type == typeof(long) || (object)type == typeof(ulong))
return JsonTypeDescription.Create(type, JsonObjectType.Integer, false, "int64");
if ((object)type == typeof(double) || (object)type == typeof(float))
return JsonTypeDescription.Create(type, JsonObjectType.Number, false, "double");
if ((object)type == typeof(decimal))
return JsonTypeDescription.Create(type, JsonObjectType.Number, false, "decimal");
if ((object)type == typeof(bool))
return JsonTypeDescription.Create(type, JsonObjectType.Boolean, false, null);
if ((object)type == typeof(string) || (object)type == typeof(Type))
return JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null);
if ((object)type == typeof(char))
return JsonTypeDescription.Create(type, JsonObjectType.String, false, null);
if ((object)type == typeof(Guid))
return JsonTypeDescription.Create(type, JsonObjectType.String, false, "guid");
if ((object)type == typeof(DateTime) || (object)type == typeof(DateTimeOffset) || type.FullName == "NodaTime.OffsetDateTime" || type.FullName == "NodaTime.LocalDateTime" || type.FullName == "NodaTime.ZonedDateTime")
return JsonTypeDescription.Create(type, JsonObjectType.String, false, "date-time");
if ((object)type == typeof(TimeSpan) || type.FullName == "NodaTime.Duration")
return JsonTypeDescription.Create(type, JsonObjectType.String, false, "time-span");
if (type.FullName == "NodaTime.LocalDate")
return JsonTypeDescription.Create(type, JsonObjectType.String, false, "date");
if (type.FullName == "NodaTime.LocalTime")
return JsonTypeDescription.Create(type, JsonObjectType.String, false, "time");
if ((object)type == typeof(Uri))
return JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, "uri");
if ((object)type == typeof(byte))
return JsonTypeDescription.Create(type, JsonObjectType.Integer, false, "byte");
if ((object)type == typeof(byte[]))
return JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, "byte");
if ((object)type == typeof(JArray))
return JsonTypeDescription.Create(type, JsonObjectType.Array, isNullable, null);
if ((object)type == typeof(JObject) || (object)type == typeof(JToken) || type.FullName == "System.Dynamic.ExpandoObject" || (object)type == typeof(object))
return JsonTypeDescription.Create(type, JsonObjectType.None, isNullable, null);
if (IsFileType(type, parentAttributes))
return JsonTypeDescription.Create(type, JsonObjectType.File, isNullable, null);
JsonContract jsonContract = settings.ResolveContract(type);
if (IsDictionaryType(type, parentAttributes) && jsonContract is JsonDictionaryContract)
return JsonTypeDescription.CreateForDictionary(type, JsonObjectType.Object, isNullable);
if (IsArrayType(type, parentAttributes) && jsonContract is JsonArrayContract)
return JsonTypeDescription.Create(type, JsonObjectType.Array, isNullable, null);
if (type.get_Name() == "Nullable`1") {
JsonTypeDescription description = GetDescription(type.GenericTypeArguments[0], (parentAttributes != null) ? (from a in parentAttributes
where !(a is JsonSchemaTypeAttribute)
select a) : null, settings);
description.IsNullable = true;
return description;
}
if (jsonContract is JsonStringContract)
return JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null);
return JsonTypeDescription.Create(type, JsonObjectType.Object, isNullable, null);
}
public virtual bool IsNullable(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaGeneratorSettings settings)
{
JsonPropertyAttribute jsonPropertyAttribute = (parentAttributes != null) ? parentAttributes.OfType<JsonPropertyAttribute>().SingleOrDefault() : null;
if (jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.DisallowNull)
return false;
if (parentAttributes.TryGetIfAssignableTo("NotNullAttribute", TypeNameStyle.Name) != null)
return false;
if (parentAttributes.TryGetIfAssignableTo("CanBeNullAttribute", TypeNameStyle.Name) != null)
return true;
if (type.get_Name() == "Nullable`1")
return true;
if ((object)type == typeof(string) || !type.GetTypeInfo().get_IsValueType())
return settings.DefaultReferenceTypeNullHandling == ReferenceTypeNullHandling.Null;
return false;
}
protected virtual bool IsFileType(Type type, IEnumerable<Attribute> parentAttributes)
{
if (!(type.get_Name() == "IFormFile") && !type.IsAssignableTo("HttpPostedFile", TypeNameStyle.Name) && !type.IsAssignableTo("HttpPostedFileBase", TypeNameStyle.Name))
return type.GetTypeInfo().ImplementedInterfaces.Any((Type i) => i.get_Name() == "IFormFile");
return true;
}
protected virtual bool IsArrayType(Type type, IEnumerable<Attribute> parentAttributes)
{
if (IsDictionaryType(type, parentAttributes))
return false;
if (type.get_Name() == "ObservableCollection`1")
return true;
if (!type.IsArray) {
if (type.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IEnumerable))) {
if ((object)type.GetTypeInfo().get_BaseType() != null)
return !type.GetTypeInfo().get_BaseType().GetTypeInfo()
.ImplementedInterfaces.Contains(typeof(IEnumerable));
return true;
}
return false;
}
return true;
}
protected virtual bool IsDictionaryType(Type type, IEnumerable<Attribute> parentAttributes)
{
if (type.get_Name() == "IDictionary`2" || type.get_Name() == "IReadOnlyDictionary`2")
return true;
if (type.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IDictionary))) {
if ((object)type.GetTypeInfo().get_BaseType() != null)
return !type.GetTypeInfo().get_BaseType().GetTypeInfo()
.ImplementedInterfaces.Contains(typeof(IDictionary));
return true;
}
return false;
}
private bool IsStringEnum(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaGeneratorSettings settings)
{
bool num = settings.ActualSerializerSettings.Converters.OfType<StringEnumConverter>().Any();
bool flag = HasStringEnumConverter(type.GetTypeInfo().GetCustomAttributes());
bool flag2 = parentAttributes != null && HasStringEnumConverter(parentAttributes);
return num | flag | flag2;
}
private bool HasStringEnumConverter(IEnumerable<Attribute> attributes)
{
if (attributes == null)
return false;
dynamic val = (attributes != null) ? attributes.FirstOrDefault((Attribute a) => a.GetType().get_Name() == "JsonConverterAttribute") : null;
if (val != null)
return ((Type)val.ConverterType).IsAssignableTo("StringEnumConverter", TypeNameStyle.Name);
return false;
}
}
}