/// <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); }
public override bool IsNullable(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling) { if (contextualType.GetContextAttribute <AlwaysPresentAttribute>() != null) { return(false); } return(base.IsNullable(contextualType, defaultReferenceTypeNullHandling)); }
/// <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)); }
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); }