예제 #1
0
        /// <summary>Checks whether a type is nullable.</summary>
        /// <param name="contextualType">The type.</param>
        /// <param name="defaultReferenceTypeNullHandling">The default reference type null handling used when no nullability information is available.</param>
        /// <returns>true if the type can be null.</returns>
        public virtual bool IsNullable(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling)
        {
            var jsonPropertyAttribute = contextualType.GetContextAttribute <JsonPropertyAttribute>();

            if (jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.DisallowNull)
            {
                return(false);
            }

            if (contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("NotNullAttribute", TypeNameStyle.Name) != null)
            {
                return(false);
            }

            if (contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("CanBeNullAttribute", TypeNameStyle.Name) != null)
            {
                return(true);
            }

            if (contextualType.Nullability != Nullability.Unknown)
            {
                return(contextualType.Nullability == Nullability.Nullable);
            }

            var isValueType = contextualType.Type != typeof(string) &&
                              contextualType.TypeInfo.IsValueType;

            return(isValueType == false &&
                   defaultReferenceTypeNullHandling != ReferenceTypeNullHandling.NotNull);
        }
예제 #2
0
 public override bool IsNullable(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling)
 {
     if (contextualType.GetContextAttribute <AlwaysPresentAttribute>() != null)
     {
         return(false);
     }
     return(base.IsNullable(contextualType, defaultReferenceTypeNullHandling));
 }
예제 #3
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));
        }
            public override JsonTypeDescription GetDescription(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings)
            {
                if (Ref.IsRefType(contextualType.Type))
                {
                    Type targetType = Ref.GetTargetType(contextualType.Type);
                    Type idType     = Ref.GetIdentifierType(targetType);
                    return(base.GetDescription(idType.ToContextualType(), defaultReferenceTypeNullHandling, settings));
                }

                return(base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings));
            }
예제 #5
0
 public override JsonTypeDescription GetDescription(ContextualType contextualType,
                                                    ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings)
 {
     return(base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings));
 }
        /// <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));
        }
        /// <summary>Checks whether a type is nullable.</summary>
        /// <param name="type">The type.</param>
        /// <param name="parentAttributes">The parent attributes (e.g. property or parameter attributes).</param>
        /// <param name="defaultReferenceTypeNullHandling">The default reference type null handling used when no nullability information is available.</param>
        /// <returns>true if the type can be null.</returns>
        public virtual bool IsNullable(Type type, IEnumerable <Attribute> parentAttributes, ReferenceTypeNullHandling defaultReferenceTypeNullHandling)
        {
            var jsonPropertyAttribute = parentAttributes?.OfType <JsonPropertyAttribute>().SingleOrDefault();

            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.Name == "Nullable`1")
            {
                return(true);
            }

            var isValueType = type != typeof(string) && type.GetTypeInfo().IsValueType;

            return(isValueType == false && defaultReferenceTypeNullHandling == ReferenceTypeNullHandling.Null);
        }