コード例 #1
0
        private void LoadEnumerations(Type type, JsonSchema4 schema, JsonTypeDescription typeDescription)
        {
            schema.Type = typeDescription.Type;
            schema.Enumeration.Clear();
            schema.EnumerationNames.Clear();

            var underlyingType = Enum.GetUnderlyingType(type);

            foreach (var enumName in Enum.GetNames(type))
            {
                if (typeDescription.Type == JsonObjectType.Integer)
                {
                    var value = Convert.ChangeType(Enum.Parse(type, enumName), underlyingType);
                    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);
            }
        }
コード例 #2
0
        private async Task GenerateEnum <TSchemaType>(
            TSchemaType schema, Type type, IEnumerable <Attribute> parentAttributes, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
            where TSchemaType : JsonSchema4, new()
        {
            if (type.Name == "Nullable`1")
#if !LEGACY
            { type = type.GenericTypeArguments[0]; }
#else
            { type = type.GetGenericArguments()[0]; }
#endif

            var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer;
            if (schemaResolver.HasSchema(type, isIntegerEnumeration))
            {
                schema.Reference = 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.Reference = await GenerateAsync(type, parentAttributes, schemaResolver).ConfigureAwait(false);
            }
        }
コード例 #3
0
        private async Task GenerateArray <TSchemaType>(
            TSchemaType schema, Type type, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
            where TSchemaType : JsonSchema4, new()
        {
            typeDescription.ApplyType(schema);

            var itemType = type.GetEnumerableItemType();

            if (itemType != null)
            {
                schema.Item = await GenerateWithReferenceAndNullability <JsonSchema4>(
#pragma warning disable 1998
                    itemType, null, false, schemaResolver, async (s, r) =>
#pragma warning restore 1998
                {
                    if (Settings.GenerateXmlObjects)
                    {
                        s.GenerateXmlObjectForItemType(itemType);
                    }
                }).ConfigureAwait(false);
            }
            else
            {
                schema.Item = JsonSchema4.CreateAnySchema();
            }
        }
コード例 #4
0
        /// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary>
        /// <param name="contextualType">The type.</param>
        /// <param name="defaultReferenceTypeNullHandling">The default reference type null handling used when no nullability information is available.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>The <see cref="JsonTypeDescription"/>. </returns>
        public virtual JsonTypeDescription GetDescription(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings)
        {
            var type       = contextualType.OriginalType;
            var isNullable = IsNullable(contextualType, defaultReferenceTypeNullHandling);

            var jsonSchemaTypeAttribute = contextualType.GetAttribute <JsonSchemaTypeAttribute>();

            if (jsonSchemaTypeAttribute != null)
            {
                type           = jsonSchemaTypeAttribute.Type;
                contextualType = type.ToContextualType();

                if (jsonSchemaTypeAttribute.IsNullableRaw.HasValue)
                {
                    isNullable = jsonSchemaTypeAttribute.IsNullableRaw.Value;
                }
            }

            var jsonSchemaAttribute = contextualType.GetAttribute <JsonSchemaAttribute>();

            if (jsonSchemaAttribute != null)
            {
                var classType = jsonSchemaAttribute.Type != JsonObjectType.None ? jsonSchemaAttribute.Type : JsonObjectType.Object;
                var format    = !string.IsNullOrEmpty(jsonSchemaAttribute.Format) ? jsonSchemaAttribute.Format : null;
                return(JsonTypeDescription.Create(contextualType, classType, isNullable, format));
            }

            if (type.GetTypeInfo().IsEnum)
            {
                var isStringEnum = IsStringEnum(contextualType, settings.ActualSerializerSettings);
                return(JsonTypeDescription.CreateForEnumeration(contextualType,
                                                                isStringEnum ? JsonObjectType.String : JsonObjectType.Integer, false));
            }

            // Primitive types

            if (type == typeof(short) ||
                type == typeof(uint) ||
                type == typeof(ushort))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, null));
            }

            if (type == typeof(int))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Integer));
            }

            if (type == typeof(long) ||
                type == typeof(ulong))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Long));
            }

            if (type == typeof(double))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Double));
            }

            if (type == typeof(float))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Float));
            }

            if (type == typeof(decimal))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Decimal));
            }

            if (type == typeof(bool))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Boolean, false, null));
            }

            if (type == typeof(string) || type == typeof(Type))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, null));
            }

            if (type == typeof(char))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, null));
            }

            if (type == typeof(Guid))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Guid));
            }

            // Date & time types

            if (type == typeof(DateTime) ||
                type == typeof(DateTimeOffset) ||
                type.FullName == "NodaTime.OffsetDateTime" ||
                type.FullName == "NodaTime.LocalDateTime" ||
                type.FullName == "NodaTime.ZonedDateTime" ||
                type.FullName == "NodaTime.Instant")
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.DateTime));
            }

            if (type == typeof(TimeSpan) ||
                type.FullName == "NodaTime.Duration")
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.TimeSpan));
            }

            if (type.FullName == "NodaTime.LocalDate")
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Date));
            }

            if (type.FullName == "NodaTime.LocalTime")
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Time));
            }

            // Special types

            if (type == typeof(Uri))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Uri));
            }

            if (type == typeof(byte))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Byte));
            }

            if (type == typeof(byte[]))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Byte));
            }

            if (type.IsAssignableToTypeName(nameof(JArray), TypeNameStyle.Name))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Array, isNullable, null));
            }

            if (type.IsAssignableToTypeName(nameof(JToken), TypeNameStyle.Name) ||
                type.FullName == "System.Dynamic.ExpandoObject" ||
                type.FullName == "System.Text.Json.JsonElement" ||
                type == typeof(object))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.None, isNullable, null));
            }

            if (IsBinary(contextualType))
            {
                if (settings.SchemaType == SchemaType.Swagger2)
                {
                    return(JsonTypeDescription.Create(contextualType, JsonObjectType.File, isNullable, null));
                }
                else
                {
                    return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Binary));
                }
            }

            if (contextualType.IsNullableType)
            {
                var typeDescription = GetDescription(contextualType.OriginalGenericArguments[0], defaultReferenceTypeNullHandling, settings);
                typeDescription.IsNullable = true;
                return(typeDescription);
            }

            var contract = settings.ResolveContract(type);

            if (IsDictionaryType(contextualType) && contract is JsonDictionaryContract)
            {
                return(JsonTypeDescription.CreateForDictionary(contextualType, JsonObjectType.Object, isNullable));
            }

            // TODO: Don't trust JsonArrayContract when contextualType is IAsyncEnumerable<T> until it is fixed
            if (IsIAsyncEnumerableType(contextualType) || (IsArrayType(contextualType) && contract is JsonArrayContract))
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.Array, isNullable, null));
            }

            if (contract is JsonStringContract)
            {
                return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, null));
            }

            return(JsonTypeDescription.Create(contextualType, JsonObjectType.Object, isNullable, null));
        }
コード例 #5
0
        /// <summary>Applies the property annotations to the JSON property.</summary>
        /// <param name="schema">The schema.</param>
        /// <param name="typeDescription">The property type description.</param>
        /// <param name="parentAttributes">The attributes.</param>
        public virtual void ApplyDataAnnotations(JsonSchema4 schema, JsonTypeDescription typeDescription, IEnumerable <Attribute> parentAttributes)
        {
            // TODO: Refactor out

            dynamic displayAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DisplayAttribute");

            if (displayAttribute != null && displayAttribute.Name != null)
            {
                schema.Title = displayAttribute.Name;
            }

            dynamic defaultValueAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DefaultValueAttribute");

            if (defaultValueAttribute != null)
            {
                schema.Default = defaultValueAttribute.Value;
            }

            dynamic regexAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RegularExpressionAttribute");

            if (regexAttribute != null)
            {
                if (typeDescription.IsDictionary)
                {
                    schema.AdditionalPropertiesSchema.Pattern = regexAttribute.Pattern;
                }
                else
                {
                    schema.Pattern = regexAttribute.Pattern;
                }
            }

            if (typeDescription.Type == JsonObjectType.Number ||
                typeDescription.Type == JsonObjectType.Integer)
            {
                dynamic rangeAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RangeAttribute");
                if (rangeAttribute != null)
                {
                    if (rangeAttribute.Minimum != null && rangeAttribute.Minimum > double.MinValue)
                    {
                        schema.Minimum = (decimal?)(double)rangeAttribute.Minimum;
                    }
                    if (rangeAttribute.Maximum != null && rangeAttribute.Maximum < double.MaxValue)
                    {
                        schema.Maximum = (decimal?)(double)rangeAttribute.Maximum;
                    }
                }

                var multipleOfAttribute = parentAttributes.OfType <MultipleOfAttribute>().SingleOrDefault();
                if (multipleOfAttribute != null)
                {
                    schema.MultipleOf = multipleOfAttribute.MultipleOf;
                }
            }

            dynamic minLengthAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MinLengthAttribute");

            if (minLengthAttribute != null && minLengthAttribute.Length != null)
            {
                if (typeDescription.Type == JsonObjectType.String)
                {
                    schema.MinLength = minLengthAttribute.Length;
                }
                else if (typeDescription.Type == JsonObjectType.Array)
                {
                    schema.MinItems = minLengthAttribute.Length;
                }
            }

            dynamic maxLengthAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MaxLengthAttribute");

            if (maxLengthAttribute != null && maxLengthAttribute.Length != null)
            {
                if (typeDescription.Type == JsonObjectType.String)
                {
                    schema.MaxLength = maxLengthAttribute.Length;
                }
                else if (typeDescription.Type == JsonObjectType.Array)
                {
                    schema.MaxItems = maxLengthAttribute.Length;
                }
            }

            dynamic stringLengthAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.StringLengthAttribute");

            if (stringLengthAttribute != null)
            {
                if (typeDescription.Type == JsonObjectType.String)
                {
                    schema.MinLength = stringLengthAttribute.MinimumLength;
                    schema.MaxLength = stringLengthAttribute.MaximumLength;
                }
            }

            dynamic dataTypeAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DataTypeAttribute");

            if (dataTypeAttribute != null)
            {
                var dataType = dataTypeAttribute.DataType.ToString();
                if (DataTypeFormats.ContainsKey(dataType))
                {
                    schema.Format = DataTypeFormats[dataType];
                }
            }
        }
コード例 #6
0
        /// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary>
        /// <param name="type">The type. </param>
        /// <param name="parentAttributes">The parent's attributes (i.e. parameter or property attributes).</param>
        /// <param name="defaultReferenceTypeNullHandling">The default reference type null handling used when no nullability information is available.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>The <see cref="JsonTypeDescription"/>. </returns>
        public virtual JsonTypeDescription GetDescription(Type type, IEnumerable <Attribute> parentAttributes,
                                                          ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings)
        {
            var isNullable = IsNullable(type, parentAttributes, defaultReferenceTypeNullHandling);

            var jsonSchemaTypeAttribute = type.GetTypeInfo().GetCustomAttribute <JsonSchemaTypeAttribute>() ??
                                          parentAttributes?.OfType <JsonSchemaTypeAttribute>().SingleOrDefault();

            if (jsonSchemaTypeAttribute != null)
            {
                type = jsonSchemaTypeAttribute.Type;

                if (jsonSchemaTypeAttribute.IsNullableRaw.HasValue)
                {
                    isNullable = jsonSchemaTypeAttribute.IsNullableRaw.Value;
                }
            }

            var jsonSchemaAttribute = type.GetTypeInfo().GetCustomAttribute <JsonSchemaAttribute>() ??
                                      parentAttributes?.OfType <JsonSchemaAttribute>().SingleOrDefault();

            if (jsonSchemaAttribute != null)
            {
                var classType = jsonSchemaAttribute.Type != JsonObjectType.None ? jsonSchemaAttribute.Type : JsonObjectType.Object;
                var format    = !string.IsNullOrEmpty(jsonSchemaAttribute.Format) ? jsonSchemaAttribute.Format : null;
                return(JsonTypeDescription.Create(type, classType, isNullable, format));
            }

            if (type.GetTypeInfo().IsEnum)
            {
                var isStringEnum = IsStringEnum(type, parentAttributes, settings);
                return(JsonTypeDescription.CreateForEnumeration(type,
                                                                isStringEnum ? JsonObjectType.String : JsonObjectType.Integer, false));
            }

            if (type == typeof(short) ||
                type == typeof(uint) ||
                type == typeof(ushort))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, null));
            }

            if (type == typeof(int))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Integer));
            }

            if (type == typeof(long) ||
                type == typeof(ulong))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Long));
            }

            if (type == typeof(double) ||
                type == typeof(float))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Number, false, JsonFormatStrings.Double));
            }

            if (type == typeof(decimal))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Number, false, JsonFormatStrings.Decimal));
            }

            if (type == typeof(bool))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Boolean, false, null));
            }

            if (type == typeof(string) || type == typeof(Type))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null));
            }

            if (type == typeof(char))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, null));
            }

            if (type == typeof(Guid))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.Guid));
            }

            if (type == typeof(DateTime) ||
                type == typeof(DateTimeOffset) ||
                type.FullName == "NodaTime.OffsetDateTime" ||
                type.FullName == "NodaTime.LocalDateTime" ||
                type.FullName == "NodaTime.ZonedDateTime" ||
                type.FullName == "NodaTime.Instant")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.DateTime));
            }

            if (type == typeof(TimeSpan) ||
                type.FullName == "NodaTime.Duration")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.TimeSpan));
            }

            if (type.FullName == "NodaTime.LocalDate")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.Date));
            }

            if (type.FullName == "NodaTime.LocalTime")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.Time));
            }

            if (type == typeof(Uri))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, JsonFormatStrings.Uri));
            }

            if (type == typeof(byte))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Byte));
            }

            if (type == typeof(byte[]))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, JsonFormatStrings.Byte));
            }

            if (type.IsAssignableTo(nameof(JArray), TypeNameStyle.Name))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Array, isNullable, null));
            }

            if (type.IsAssignableTo(nameof(JToken), TypeNameStyle.Name) ||
                type.FullName == "System.Dynamic.ExpandoObject" ||
                type == typeof(object))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.None, isNullable, null));
            }

            if (IsBinary(type, parentAttributes))
            {
                if (settings.SchemaType == SchemaType.Swagger2)
                {
                    return(JsonTypeDescription.Create(type, JsonObjectType.File, isNullable, null));
                }
                else
                {
                    return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, JsonFormatStrings.Binary));
                }
            }

            var contract = settings.ResolveContract(type);

            if (IsDictionaryType(type, parentAttributes) && contract is JsonDictionaryContract)
            {
                return(JsonTypeDescription.CreateForDictionary(type, JsonObjectType.Object, isNullable));
            }

            if (IsArrayType(type, parentAttributes) && contract is JsonArrayContract)
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Array, isNullable, null));
            }

            if (type.Name == "Nullable`1")
            {
#if !LEGACY
                // Remove JsonSchemaTypeAttributes to avoid stack overflows
                var typeDescription = GetDescription(type.GenericTypeArguments[0], parentAttributes?.Where(a => !(a is JsonSchemaTypeAttribute)), defaultReferenceTypeNullHandling, settings);
#else
                var typeDescription = GetDescription(type.GetGenericArguments()[0], parentAttributes?.Where(a => !(a is JsonSchemaTypeAttribute)), defaultReferenceTypeNullHandling, settings);
#endif
                typeDescription.IsNullable = true;
                return(typeDescription);
            }

            if (contract is JsonStringContract)
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null));
            }

            return(JsonTypeDescription.Create(type, JsonObjectType.Object, isNullable, null));
        }
コード例 #7
0
        /// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary>
        /// <param name="type">The type. </param>
        /// <param name="parentAttributes">The parent's attributes (i.e. parameter or property attributes).</param>
        /// <param name="settings">The settings.</param>
        /// <returns>The <see cref="JsonTypeDescription"/>. </returns>
        public virtual JsonTypeDescription GetDescription(Type type, IEnumerable <Attribute> parentAttributes, JsonSchemaGeneratorSettings settings)
        {
            if (type.GetTypeInfo().IsEnum)
            {
                var isStringEnum = IsStringEnum(type, parentAttributes, settings.DefaultEnumHandling);
                return(JsonTypeDescription.CreateForEnumeration(type,
                                                                isStringEnum ? JsonObjectType.String : JsonObjectType.Integer, false));
            }

            if (type == typeof(short) || type == typeof(uint) || type == typeof(ushort))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, null));
            }

            if (type == typeof(int))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Integer));
            }

            if ((type == typeof(long)) || (type == typeof(ulong)))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Long));
            }

            if (type == typeof(double) || type == typeof(float))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Number, false, JsonFormatStrings.Double));
            }

            if (type == typeof(decimal))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Number, false, JsonFormatStrings.Decimal));
            }

            if (type == typeof(bool))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Boolean, false, null));
            }

            var isNullable = IsNullable(type, parentAttributes, settings);

            if (type == typeof(string) || type == typeof(Type))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null));
            }

            if (type == typeof(char))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, null));
            }

            if (type == typeof(Guid))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.Guid));
            }

            if (type == typeof(DateTime) || type == typeof(DateTimeOffset) || type.FullName == "NodaTime.OffsetDateTime" || type.FullName == "NodaTime.ZonedDateTime")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.DateTime));
            }

            if (type == typeof(TimeSpan) || type.FullName == "NodaTime.Duration")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.TimeSpan));
            }

            if (type.FullName == "NodaTime.LocalDate")
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, false, JsonFormatStrings.Date));
            }

            if (type == typeof(Uri))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, JsonFormatStrings.Uri));
            }

            if (type == typeof(byte))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Integer, false, JsonFormatStrings.Byte));
            }

            if (type == typeof(byte[]))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, JsonFormatStrings.Byte));
            }

            if (type == typeof(JObject) || type == typeof(JToken) || type == typeof(object))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.None, isNullable, null));
            }

            if (IsFileType(type, parentAttributes))
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.File, isNullable, null));
            }

            var contract = settings.ResolveContract(type);

            if (IsDictionaryType(type, parentAttributes) && contract is JsonDictionaryContract)
            {
                return(JsonTypeDescription.CreateForDictionary(type, JsonObjectType.Object, isNullable));
            }

            if (IsArrayType(type, parentAttributes) && contract is JsonArrayContract)
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.Array, isNullable, null));
            }

            if (type.Name == "Nullable`1")
            {
#if !LEGACY
                var typeDescription = GetDescription(type.GenericTypeArguments[0], parentAttributes, settings);
#else
                var typeDescription = GetDescription(type.GetGenericArguments()[0], parentAttributes, settings);
#endif
                typeDescription.IsNullable = true;
                return(typeDescription);
            }

            var jsonSchemaAttribute = type.GetTypeInfo().GetCustomAttribute <JsonSchemaAttribute>() ??
                                      parentAttributes?.OfType <JsonSchemaAttribute>().SingleOrDefault();
            if (jsonSchemaAttribute != null)
            {
                var classType = jsonSchemaAttribute.Type != JsonObjectType.None ? jsonSchemaAttribute.Type : JsonObjectType.Object;
                var format    = !string.IsNullOrEmpty(jsonSchemaAttribute.Format) ? jsonSchemaAttribute.Format : null;
                return(JsonTypeDescription.Create(type, classType, isNullable, format));
            }

            if (contract is JsonStringContract)
            {
                return(JsonTypeDescription.Create(type, JsonObjectType.String, isNullable, null));
            }

            return(JsonTypeDescription.Create(type, JsonObjectType.Object, isNullable, null));
        }