diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 308bfd7d1..c715be50b 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -22,6 +22,7 @@ latest true + enable diff --git a/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj b/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj index 4e09ea592..dcd071859 100644 --- a/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj +++ b/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj @@ -1,35 +1,36 @@  - - - net6.0 - false - $(NoWarn),xUnit1013 - false - - - - + + net6.0 + false + $(NoWarn),xUnit1013 + false + disable + - - - - - - - - + + + - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/NJsonSchema.CodeGeneration.CSharp.Tests.csproj b/src/NJsonSchema.CodeGeneration.CSharp.Tests/NJsonSchema.CodeGeneration.CSharp.Tests.csproj index 895cd227d..91e7723c3 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp.Tests/NJsonSchema.CodeGeneration.CSharp.Tests.csproj +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/NJsonSchema.CodeGeneration.CSharp.Tests.csproj @@ -1,27 +1,28 @@  - - net6.0 - false - true - $(NoWarn),1587,1998,1591,618,SYSLIB0012 - + + net6.0 + false + true + $(NoWarn),1587,1998,1591,618,SYSLIB0012 + disable + - - - + + + - - - - - - - + + + + + + + - - - - + + + + diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs index 7ccbfdaeb..285e6a221 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs @@ -125,7 +125,7 @@ private CodeArtifact GenerateClass(JsonSchema schema, string typeName) private static void RenamePropertyWithSameNameAsClass(string typeName, IEnumerable properties) { var propertyModels = properties as PropertyModel[] ?? properties.ToArray(); - PropertyModel propertyWithSameNameAsClass = null; + PropertyModel? propertyWithSameNameAsClass = null; foreach (var p in propertyModels) { if (p.PropertyName == typeName) diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs index 7479567c3..8c486e879 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs @@ -110,7 +110,7 @@ public CSharpGeneratorSettings() public string PropertySetterAccessModifier { get; set; } /// Gets or sets the custom Json.NET converters (class names) which are registered for serialization and deserialization. - public string[] JsonConverters { get; set; } + public string[]? JsonConverters { get; set; } /// Gets or sets a value indicating whether to remove the setter for non-nullable array properties (default: false). public bool GenerateImmutableArrayProperties { get; set; } @@ -122,7 +122,7 @@ public CSharpGeneratorSettings() public bool HandleReferences { get; set; } /// Gets or sets the name of a static method which is called to transform the JsonSerializerSettings (for Newtonsoft.Json) or the JsonSerializerOptions (for System.Text.Json) used in the generated ToJson()/FromJson() methods (default: null). - public string JsonSerializerSettingsTransformationMethod { get; set; } + public string? JsonSerializerSettingsTransformationMethod { get; set; } /// Gets or sets a value indicating whether to render ToJson() and FromJson() methods (default: false). public bool GenerateJsonMethods { get; set; } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonSerializerGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonSerializerGenerator.cs index 789e85705..1f13fd59e 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonSerializerGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonSerializerGenerator.cs @@ -19,7 +19,7 @@ public static class CSharpJsonSerializerGenerator /// The settings. /// The additional JSON converters. /// The code. - public static string GenerateJsonSerializerParameterCode(CSharpGeneratorSettings settings, IEnumerable additionalJsonConverters) + public static string GenerateJsonSerializerParameterCode(CSharpGeneratorSettings settings, IEnumerable? additionalJsonConverters) { var jsonConverters = GetJsonConverters(settings, additionalJsonConverters); var hasJsonConverters = jsonConverters.Any(); @@ -31,14 +31,14 @@ public static string GenerateJsonSerializerParameterCode(CSharpGeneratorSettings /// The settings. /// The additional JSON converters. /// The code. - public static string GenerateJsonConvertersArrayCode(CSharpGeneratorSettings settings, IEnumerable additionalJsonConverters) + public static string GenerateJsonConvertersArrayCode(CSharpGeneratorSettings settings, IEnumerable? additionalJsonConverters) { var jsonConverters = GetJsonConverters(settings, additionalJsonConverters); return GenerateConverters(jsonConverters, settings.JsonLibrary); } - private static List GetJsonConverters(CSharpGeneratorSettings settings, IEnumerable additionalJsonConverters) + private static List GetJsonConverters(CSharpGeneratorSettings settings, IEnumerable? additionalJsonConverters) { return (settings.JsonConverters ?? Array.Empty()).Concat(additionalJsonConverters ?? Array.Empty()).ToList(); } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs index 6038575f4..fab7be3a6 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs @@ -24,7 +24,7 @@ public CSharpTypeResolver(CSharpGeneratorSettings settings) /// Initializes a new instance of the class. /// The generator settings. /// The exception type schema. - public CSharpTypeResolver(CSharpGeneratorSettings settings, JsonSchema exceptionSchema) + public CSharpTypeResolver(CSharpGeneratorSettings settings, JsonSchema? exceptionSchema) : base(settings) { Settings = settings; @@ -32,7 +32,7 @@ public CSharpTypeResolver(CSharpGeneratorSettings settings, JsonSchema exception } /// Gets the exception schema. - public JsonSchema ExceptionSchema { get; } + public JsonSchema? ExceptionSchema { get; } /// Gets the generator settings. public CSharpGeneratorSettings Settings { get; } @@ -42,7 +42,7 @@ public CSharpTypeResolver(CSharpGeneratorSettings settings, JsonSchema exception /// Specifies whether the given type usage is nullable. /// The type name hint to use when generating the type and the type name is missing. /// The type name. - public override string Resolve(JsonSchema schema, bool isNullable, string typeNameHint) + public override string Resolve(JsonSchema schema, bool isNullable, string? typeNameHint) { return Resolve(schema, isNullable, typeNameHint, true); } @@ -53,7 +53,7 @@ public override string Resolve(JsonSchema schema, bool isNullable, string typeNa /// The type name hint to use when generating the type and the type name is missing. /// Checks whether a named schema is already registered. /// The type name. - public string Resolve(JsonSchema schema, bool isNullable, string typeNameHint, bool checkForExistingSchema) + public string Resolve(JsonSchema schema, bool isNullable, string? typeNameHint, bool checkForExistingSchema) { if (schema == null) { @@ -158,7 +158,7 @@ protected override bool IsDefinitionTypeSchema(JsonSchema schema) return base.IsDefinitionTypeSchema(schema); } - private string ResolveString(JsonSchema schema, bool isNullable, string typeNameHint) + private string ResolveString(JsonSchema schema, bool isNullable, string? typeNameHint) { var nullableReferenceType = Settings.GenerateNullableReferenceTypes && isNullable ? "?" : string.Empty; @@ -209,7 +209,7 @@ private static string ResolveBoolean(bool isNullable) return isNullable ? "bool?" : "bool"; } - private string ResolveInteger(JsonSchema schema, bool isNullable, string typeNameHint) + private string ResolveInteger(JsonSchema schema, bool isNullable, string? typeNameHint) { if (schema.Format == JsonFormatStrings.Byte) { diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs index 6c21eb7fc..4ae5598df 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs @@ -38,7 +38,7 @@ public CSharpValueGenerator(CSharpGeneratorSettings settings) /// if set to true uses the default value from the schema if available. /// The type resolver. /// The code. - public override string GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) + public override string? GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string? typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) { var value = base.GetDefaultValue(schema, allowsNull, targetType, typeNameHint, useSchemaDefault, typeResolver); if (value == null) @@ -87,32 +87,27 @@ public override string GetDefaultValue(JsonSchema schema, bool allowsNull, strin /// The value to convert. /// Optional schema format /// The C# number literal. - public override string GetNumericValue(JsonObjectType type, object value, string format) + public override string GetNumericValue(JsonObjectType type, object value, string? format) { - if (value != null) + switch (format) { - switch (format) - { - case JsonFormatStrings.Byte: - return "(byte)" + Convert.ToByte(value).ToString(CultureInfo.InvariantCulture); - case JsonFormatStrings.Integer: - return Convert.ToInt32(value).ToString(CultureInfo.InvariantCulture); - case JsonFormatStrings.Long: - return Convert.ToInt64(value) + "L"; - case JsonFormatStrings.Double: - return ConvertNumberToString(value) + "D"; - case JsonFormatStrings.Float: - return ConvertNumberToString(value) + "F"; - case JsonFormatStrings.Decimal: - return ConvertNumberToString(value) + "M"; - default: - return type.IsInteger() ? - ConvertNumberToString(value) : - ConvertNumberToString(value) + "D"; - } + case JsonFormatStrings.Byte: + return "(byte)" + Convert.ToByte(value).ToString(CultureInfo.InvariantCulture); + case JsonFormatStrings.Integer: + return Convert.ToInt32(value).ToString(CultureInfo.InvariantCulture); + case JsonFormatStrings.Long: + return Convert.ToInt64(value) + "L"; + case JsonFormatStrings.Double: + return ConvertNumberToString(value) + "D"; + case JsonFormatStrings.Float: + return ConvertNumberToString(value) + "F"; + case JsonFormatStrings.Decimal: + return ConvertNumberToString(value) + "M"; + default: + return type.IsInteger() ? + ConvertNumberToString(value) : + ConvertNumberToString(value) + "D"; } - - return null; } /// Gets the enum default value. @@ -121,7 +116,7 @@ public override string GetNumericValue(JsonObjectType type, object value, string /// The type name hint. /// The type resolver. /// The enum default value. - protected override string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string typeNameHint, TypeResolverBase typeResolver) + protected override string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string? typeNameHint, TypeResolverBase typeResolver) { return _settings.Namespace + "." + base.GetEnumDefaultValue(schema, actualSchema, typeNameHint, typeResolver); } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs index 17704a44e..ef3983f1b 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs @@ -41,7 +41,7 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, if (schema.InheritedSchema != null) { - BaseClass = new ClassTemplateModel(BaseClassName, settings, resolver, schema.InheritedSchema, rootObject); + BaseClass = new ClassTemplateModel(BaseClassName!, settings, resolver, schema.InheritedSchema, rootObject); AllProperties = Properties.Concat(BaseClass.AllProperties).ToArray(); } else @@ -79,7 +79,7 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, public bool GenerateAdditionalPropertiesProperty => HasAdditionalPropertiesType && !HasAdditionalPropertiesTypeInBaseClass; /// Gets the type of the additional properties. - public string AdditionalPropertiesType => HasAdditionalPropertiesType ? "object" : null; // TODO: Find a way to use typed dictionaries + public string? AdditionalPropertiesType => HasAdditionalPropertiesType ? "object" : null; // TODO: Find a way to use typed dictionaries //public string AdditionalPropertiesType => HasAdditionalPropertiesType ? _resolver.Resolve( // _schema.AdditionalPropertiesSchema, // _schema.AdditionalPropertiesSchema.IsNullable(_settings.SchemaType), @@ -97,7 +97,7 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, !string.IsNullOrEmpty(_schema.ActualTypeSchema.Description)); /// Gets the description. - public string Description => !string.IsNullOrEmpty(_schema.Description) ? + public string? Description => !string.IsNullOrEmpty(_schema.Description) ? _schema.Description : _schema.ActualTypeSchema.Description; /// Gets a value indicating whether the class style is INPC. @@ -119,7 +119,7 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, public bool HasDiscriminator => !string.IsNullOrEmpty(_schema.ActualDiscriminator); /// Gets the discriminator property name. - public string Discriminator => _schema.ActualDiscriminator; + public string? Discriminator => _schema.ActualDiscriminator; /// Gets a value indicating whether this class represents a tuple. public bool IsTuple => _schema.ActualTypeSchema.IsTuple; @@ -133,12 +133,12 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, public bool HasInheritance => _schema.InheritedTypeSchema != null; /// Gets the base class name. - public string BaseClassName => HasInheritance ? _resolver.Resolve(_schema.InheritedTypeSchema, false, string.Empty, false) - .Replace(_settings.ArrayType + "<", _settings.ArrayBaseType + "<") - .Replace(_settings.DictionaryType + "<", _settings.DictionaryBaseType + "<") : null; + public string? BaseClassName => HasInheritance ? _resolver.Resolve(_schema.InheritedTypeSchema!, false, string.Empty, false) + .Replace(_settings.ArrayType + "<", _settings.ArrayBaseType + "<") + .Replace(_settings.DictionaryType + "<", _settings.DictionaryBaseType + "<") : null; /// Gets the base class model. - public ClassTemplateModel BaseClass { get; } + public ClassTemplateModel? BaseClass { get; } /// Gets a value indicating whether the class inherits from exception. public bool InheritsExceptionSchema => _resolver.ExceptionSchema != null && @@ -166,6 +166,6 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, public bool HasDeprecatedMessage => !string.IsNullOrEmpty(_schema.DeprecatedMessage); /// Gets the deprecated message. - public string DeprecatedMessage => _schema.DeprecatedMessage; + public string? DeprecatedMessage => _schema.DeprecatedMessage; } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs index 7d2c3a85c..d61dba0d7 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs @@ -38,10 +38,10 @@ public EnumTemplateModel(string typeName, JsonSchema schema, CSharpGeneratorSett public bool HasDescription => !(_schema is JsonSchemaProperty) && !string.IsNullOrEmpty(_schema.Description); /// Gets the description. - public string Description => _schema.Description; + public string? Description => _schema.Description; /// Gets the property extension data. - public IDictionary ExtensionData => _schema.ExtensionData; + public IDictionary? ExtensionData => _schema.ExtensionData; /// Gets a value indicating whether the enum is of type string. public bool IsStringEnum => _schema.Type != JsonObjectType.Integer; diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs index 5a27111d4..1b3208427 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs @@ -12,12 +12,12 @@ namespace NJsonSchema.CodeGeneration.CSharp.Models public class FileTemplateModel { /// Gets or sets the namespace. - public string Namespace { get; set; } + public required string Namespace { get; set; } /// Gets or sets a value indicating whether the C#8 nullable reference types are enabled for this file. public bool GenerateNullableReferenceTypes { get; set; } /// Gets or sets the types code. - public string TypesCode { get; set; } + public required string TypesCode { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs index efc9da6bc..125a24c7b 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs @@ -45,7 +45,7 @@ public PropertyModel( public bool HasDescription => !string.IsNullOrEmpty(_property.Description); /// Gets the description. - public string Description => _property.Description; + public string? Description => _property.Description; /// Gets the name of the field. public string FieldName => "_" + ConversionUtilities.ConvertToLowerCamelCase(PropertyName, true); @@ -69,7 +69,7 @@ public PropertyModel( public bool HasJsonIgnoreCondition => JsonIgnoreCondition != null; /// Returns the System.Text.Json.Serialization.JsonIgnoreCondition value to be applied to the property. - public string JsonIgnoreCondition => _property switch + public string? JsonIgnoreCondition => _property switch { { IsRequired: false } => "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault", { IsRequired: true } when _settings.RequiredPropertiesMustBeDefined => "System.Text.Json.Serialization.JsonIgnoreCondition.Never", @@ -283,7 +283,7 @@ public bool RenderRegularExpressionAttribute } /// Gets the regular expression value for the regular expression attribute. - public string RegularExpressionValue => _property.ActualSchema.Pattern?.Replace("\"", "\"\""); + public string? RegularExpressionValue => _property.ActualSchema.Pattern?.Replace("\"", "\"\""); /// Gets a value indicating whether the property type is string enum. public bool IsStringEnum => _property.ActualTypeSchema.IsEnumeration && _property.ActualTypeSchema.Type.IsString(); @@ -298,9 +298,9 @@ public bool RenderRegularExpressionAttribute public bool HasDeprecatedMessage => !string.IsNullOrEmpty(_property.DeprecatedMessage); /// Gets the deprecated message. - public string DeprecatedMessage => _property.DeprecatedMessage; + public string? DeprecatedMessage => _property.DeprecatedMessage; - private string GetSchemaFormat(JsonSchema schema) + private string? GetSchemaFormat(JsonSchema schema) { if (Type == "long" || Type == "long?") { diff --git a/src/NJsonSchema.CodeGeneration.Tests/NJsonSchema.CodeGeneration.Tests.csproj b/src/NJsonSchema.CodeGeneration.Tests/NJsonSchema.CodeGeneration.Tests.csproj index da2e31952..a688110fd 100644 --- a/src/NJsonSchema.CodeGeneration.Tests/NJsonSchema.CodeGeneration.Tests.csproj +++ b/src/NJsonSchema.CodeGeneration.Tests/NJsonSchema.CodeGeneration.Tests.csproj @@ -1,35 +1,36 @@  - - - net6.0;net462 - false - $(NoWarn),1998,1591,618 - - - - - - - - + + net6.0;net462 + false + $(NoWarn),1998,1591,618 + disable + - - - + + + + + + + - - - + + + - - - - - + + + + + + + + + + + + + - - - - diff --git a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/NJsonSchema.CodeGeneration.TypeScript.Tests.csproj b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/NJsonSchema.CodeGeneration.TypeScript.Tests.csproj index e1a9d4ba3..7deab23d1 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/NJsonSchema.CodeGeneration.TypeScript.Tests.csproj +++ b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/NJsonSchema.CodeGeneration.TypeScript.Tests.csproj @@ -1,28 +1,29 @@  - - net6.0;net462 - false - true - $(NoWarn),1587,1998,1591,618 - + + net6.0;net462 + false + true + $(NoWarn),1587,1998,1591,618 + disable + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionGenerator.cs b/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionGenerator.cs index 5d15d0ec1..f388a0b88 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionGenerator.cs @@ -36,9 +36,13 @@ private static object CreateModel(DataConversionParameters parameters) var type = parameters.Resolver.Resolve(parameters.Schema, parameters.IsPropertyNullable, parameters.TypeNameHint); var valueGenerator = parameters.Settings.ValueGenerator; - var typeSchema = parameters.Schema.ActualTypeSchema; - var dictionaryValueType = parameters.Resolver.TryResolve(typeSchema.AdditionalPropertiesSchema, parameters.TypeNameHint) ?? "any"; - var dictionaryValueDefaultValue = typeSchema.AdditionalPropertiesSchema != null + JsonSchema typeSchema = parameters.Schema.ActualTypeSchema; + + var dictionaryValueType = typeSchema.AdditionalPropertiesSchema != null ? + parameters.Resolver.TryResolve(typeSchema.AdditionalPropertiesSchema, parameters.TypeNameHint) ?? "any" : + null; + + var dictionaryValueDefaultValue = typeSchema.AdditionalPropertiesSchema != null && dictionaryValueType != null ? valueGenerator.GetDefaultValue(typeSchema.AdditionalPropertiesSchema, typeSchema.AdditionalPropertiesSchema.IsNullable(parameters.Settings.SchemaType), dictionaryValueType, parameters.TypeNameHint, parameters.Settings.GenerateDefaultValues, parameters.Resolver) @@ -63,6 +67,7 @@ private static object CreateModel(DataConversionParameters parameters) IsDate = IsDate(typeSchema.Format, parameters.Settings.DateTimeType), IsDateTime = IsDateTime(typeSchema.Format, parameters.Settings.DateTimeType), + // Dictionary IsDictionary = typeSchema.IsDictionary, DictionaryValueType = dictionaryValueType, DictionaryValueDefaultValue = dictionaryValueDefaultValue, @@ -71,11 +76,18 @@ private static object CreateModel(DataConversionParameters parameters) IsDictionaryValueNewableObject = typeSchema.AdditionalPropertiesSchema != null && IsNewableObject(typeSchema.AdditionalPropertiesSchema, parameters), IsDictionaryValueDate = IsDate(typeSchema.AdditionalPropertiesSchema?.ActualSchema?.Format, parameters.Settings.DateTimeType), IsDictionaryValueDateTime = IsDateTime(typeSchema.AdditionalPropertiesSchema?.ActualSchema?.Format, parameters.Settings.DateTimeType), - IsDictionaryValueNewableArray = typeSchema.AdditionalPropertiesSchema?.ActualSchema?.IsArray == true && + + IsDictionaryValueNewableArray = + typeSchema.AdditionalPropertiesSchema?.ActualSchema?.IsArray == true && + typeSchema.AdditionalPropertiesSchema.Item != null && IsNewableObject(typeSchema.AdditionalPropertiesSchema.Item, parameters), - DictionaryValueArrayItemType = typeSchema.AdditionalPropertiesSchema?.ActualSchema?.IsArray == true ? - parameters.Resolver.TryResolve(typeSchema.AdditionalPropertiesSchema.Item, "Anonymous") ?? "any" : "any", - + + DictionaryValueArrayItemType = + typeSchema.AdditionalPropertiesSchema?.ActualSchema?.IsArray == true ? + parameters.Resolver.TryResolve(typeSchema.AdditionalPropertiesSchema.Item, "Anonymous") ?? "any" : + "any", + + // Array IsArray = typeSchema.IsArray, ArrayItemType = parameters.Resolver.TryResolve(typeSchema.Item, parameters.TypeNameHint) ?? "any", IsArrayItemNewableObject = typeSchema.Item != null && IsNewableObject(typeSchema.Item, parameters), @@ -84,12 +96,13 @@ private static object CreateModel(DataConversionParameters parameters) RequiresStrictPropertyInitialization = parameters.Settings.TypeScriptVersion >= 2.7m, + // Dates //StringToDateCode is used for date and date-time formats UseJsDate = parameters.Settings.DateTimeType == TypeScriptDateTimeType.Date, StringToDateCode = GetStringToDateTime(parameters, typeSchema), - StringToDateOnlyCode = parameters.Settings.DateTimeType == TypeScriptDateTimeType.Date - && parameters.Settings.ConvertDateToLocalTimezone - ? "parseDateOnly" + StringToDateOnlyCode = parameters.Settings.DateTimeType == TypeScriptDateTimeType.Date + && parameters.Settings.ConvertDateToLocalTimezone + ? "parseDateOnly" : GetStringToDateTime(parameters, typeSchema), DateToStringCode = GetDateToString(parameters, typeSchema), DateTimeToStringCode = GetDateTimeToString(parameters, typeSchema), @@ -197,7 +210,7 @@ private static string GetDateTimeToString(DataConversionParameters parameters, J } } - private static bool IsDateTime(string format, TypeScriptDateTimeType type) + private static bool IsDateTime(string? format, TypeScriptDateTimeType type) { // TODO: Make this more generic (see TypeScriptTypeResolver.ResolveString) if (type == TypeScriptDateTimeType.Date) @@ -257,7 +270,7 @@ private static bool IsDateTime(string format, TypeScriptDateTimeType type) } - private static bool IsDate(string format, TypeScriptDateTimeType type) + private static bool IsDate(string? format, TypeScriptDateTimeType type) { // TODO: Make this more generic (see TypeScriptTypeResolver.ResolveString) if (type == TypeScriptDateTimeType.Date) @@ -286,14 +299,19 @@ private static bool IsDate(string format, TypeScriptDateTimeType type) return false; } - private static bool IsNewableObject(JsonSchema schema, DataConversionParameters parameters) + private static bool IsNewableObject(JsonSchema? schema, DataConversionParameters parameters) { - if (schema.ActualTypeSchema.IsEnumeration) + if (schema != null) { - return false; + if (schema.ActualTypeSchema.IsEnumeration) + { + return false; + } + + return parameters.Resolver.GeneratesType(schema); } - return parameters.Resolver.GeneratesType(schema); + return false; } } } diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionParameters.cs b/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionParameters.cs index e30256f3e..b17e5fcfc 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionParameters.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/DataConversionParameters.cs @@ -12,13 +12,13 @@ namespace NJsonSchema.CodeGeneration.TypeScript public class DataConversionParameters { /// Gets the variable. - public string Variable { get; set; } + public string? Variable { get; set; } /// Gets the value. - public string Value { get; set; } + public string? Value { get; set; } /// Gets the schema. - public JsonSchema Schema { get; set; } + public required JsonSchema Schema { get; set; } /// Gets a value indicating whether the property is nullable. public bool IsPropertyNullable { get; set; } @@ -27,15 +27,15 @@ public class DataConversionParameters public bool CheckNewableObject { get; set; } = true; /// Gets the type name hint. - public string TypeNameHint { get; set; } + public string? TypeNameHint { get; set; } /// Gets the resolver. - public TypeScriptTypeResolver Resolver { get; set; } + public required TypeScriptTypeResolver Resolver { get; set; } /// Gets or sets the null value. public TypeScriptNullValue NullValue { get; set; } /// Gets or sets the settings. - public TypeScriptGeneratorSettings Settings { get; set; } + public required TypeScriptGeneratorSettings Settings { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs b/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs index 588642d23..48ce8df29 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs @@ -50,7 +50,7 @@ public ClassTemplateModel(string typeName, string discriminatorName, /// Gets the name for the discriminator check. public string DiscriminatorName => HasBaseDiscriminator ? - (_schema.ResponsibleDiscriminatorObject.Mapping.FirstOrDefault(m => m.Value.ActualTypeSchema == _schema.ActualTypeSchema).Key ?? _discriminatorName) : + (_schema.ResponsibleDiscriminatorObject!.Mapping.FirstOrDefault(m => m.Value.ActualTypeSchema == _schema.ActualTypeSchema).Key ?? _discriminatorName) : _discriminatorName; /// Gets a value indicating whether the class has a discriminator property. @@ -60,7 +60,7 @@ public ClassTemplateModel(string typeName, string discriminatorName, public bool HasBaseDiscriminator => _schema.ResponsibleDiscriminatorObject != null; /// Gets the class discriminator property name (may be defined in a inherited class). - public string BaseDiscriminator => _schema.ResponsibleDiscriminatorObject?.PropertyName; + public string? BaseDiscriminator => _schema.ResponsibleDiscriminatorObject?.PropertyName; /// Gets a value indicating whether the class has description. public bool HasDescription => !(_schema is JsonSchemaProperty) && @@ -95,7 +95,7 @@ public string Inheritance public string InterfaceInheritance => HasInheritance ? " extends I" + BaseClass : string.Empty; /// Gets the base class name. - public string BaseClass => HasInheritance ? _resolver.Resolve(InheritedSchema, true, string.Empty) : null; + public string? BaseClass => HasInheritance ? _resolver.Resolve(InheritedSchema!, true, string.Empty) : null; /// Gets or sets a value indicating whether a clone() method should be generated in the DTO classes. public bool GenerateCloneMethod => _settings.GenerateCloneMethod; @@ -155,6 +155,6 @@ public string IndexerPropertyValueType public bool GenerateTypeCheckFunctions => _settings.GenerateTypeCheckFunctions; /// Gets the inherited schema. - private JsonSchema InheritedSchema => _schema.InheritedSchema?.ActualSchema; + private JsonSchema? InheritedSchema => _schema.InheritedSchema?.ActualSchema; } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Models/EnumTemplateModel.cs b/src/NJsonSchema.CodeGeneration.TypeScript/Models/EnumTemplateModel.cs index 6ded8fef1..e2a7483b4 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Models/EnumTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Models/EnumTemplateModel.cs @@ -42,7 +42,7 @@ public EnumTemplateModel(string typeName, JsonSchema schema, TypeScriptGenerator public bool ExportTypes => _settings.ExportTypes; /// Gets the property extension data. - public IDictionary ExtensionData => _schema.ExtensionData; + public IDictionary? ExtensionData => _schema.ExtensionData; /// Gets the enum values. public List Enums diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Models/FileTemplateModel.cs b/src/NJsonSchema.CodeGeneration.TypeScript/Models/FileTemplateModel.cs index 0d33893a3..1aef6ec73 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Models/FileTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Models/FileTemplateModel.cs @@ -21,10 +21,10 @@ public FileTemplateModel(TypeScriptGeneratorSettings settings) } /// Gets or sets the code of all types. - public string Types { get; set; } + public required string Types { get; set; } /// Gets or sets the extension code. - public TypeScriptExtensionCode ExtensionCode { get; set; } + public TypeScriptExtensionCode? ExtensionCode { get; set; } /// Gets or sets a value indicating whether the file has module name. public bool HasModuleName => !string.IsNullOrEmpty(_settings.ModuleName); diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Models/PropertyModel.cs b/src/NJsonSchema.CodeGeneration.TypeScript/Models/PropertyModel.cs index b2af82210..f1e07c252 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Models/PropertyModel.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Models/PropertyModel.cs @@ -48,7 +48,7 @@ public PropertyModel( public bool HasDescription => !string.IsNullOrEmpty(Description); /// Gets the description. - public string Description => _property.Description; + public string? Description => _property.Description; /// Gets the type of the property. public override string Type => _resolver.Resolve(_property, _property.IsNullable(_settings.SchemaType), GetTypeNameHint()); @@ -71,13 +71,13 @@ public bool SupportsConstructorConversion if (IsArray) { return _resolver.SupportsConstructorConversion(_property.ActualTypeSchema?.Item) && - _property.ActualTypeSchema?.Item.ActualSchema.Type.IsObject() == true; + _property.ActualTypeSchema?.Item?.ActualSchema.Type.IsObject() == true; } if (IsDictionary) { return _resolver.SupportsConstructorConversion(_property.ActualTypeSchema?.AdditionalPropertiesSchema) && - _property.ActualTypeSchema?.AdditionalPropertiesSchema.ActualSchema.Type.IsObject() == true; + _property.ActualTypeSchema?.AdditionalPropertiesSchema?.ActualSchema.Type.IsObject() == true; } return _resolver.SupportsConstructorConversion(_property) && diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptExtensionCode.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptExtensionCode.cs index 2cf973c9f..64a935b3d 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptExtensionCode.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptExtensionCode.cs @@ -10,7 +10,7 @@ public class TypeScriptExtensionCode : ExtensionCode /// The code. /// The extended classes. /// The base classes. - public TypeScriptExtensionCode(string code, string[] extendedClasses, string[] baseClasses = null) + public TypeScriptExtensionCode(string code, string[] extendedClasses, string[]? baseClasses = null) { code = "\n" + code .Replace("\r", string.Empty) diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs index 3a080f141..2b74f1f10 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs @@ -18,7 +18,7 @@ namespace NJsonSchema.CodeGeneration.TypeScript public class TypeScriptGenerator : GeneratorBase { private readonly TypeScriptTypeResolver _resolver; - private TypeScriptExtensionCode _extensionCode; + private TypeScriptExtensionCode? _extensionCode; /// Initializes a new instance of the class. /// The schema. diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs index 5901cc795..b8e430a20 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs @@ -28,7 +28,7 @@ public TypeScriptTypeResolver(TypeScriptGeneratorSettings settings) public TypeScriptGeneratorSettings Settings { get; } /// Gets or sets the namespace of the generated classes. - public string Namespace { get; set; } + public string? Namespace { get; set; } /// Resolves and possibly generates the specified schema. Returns the type name with a 'I' prefix if the feature is supported for the given schema. /// The schema. @@ -36,7 +36,7 @@ public TypeScriptTypeResolver(TypeScriptGeneratorSettings settings) /// The type name hint to use when generating the type and the type name is missing. /// The type name. /// is . - public string ResolveConstructorInterfaceName(JsonSchema schema, bool isNullable, string typeNameHint) + public string ResolveConstructorInterfaceName(JsonSchema schema, bool isNullable, string? typeNameHint) { return Resolve(schema, typeNameHint, true); } @@ -47,7 +47,7 @@ public string ResolveConstructorInterfaceName(JsonSchema schema, bool isNullable /// The type name hint to use when generating the type and the type name is missing. /// The type name. /// is . - public override string Resolve(JsonSchema schema, bool isNullable, string typeNameHint) + public override string Resolve(JsonSchema schema, bool isNullable, string? typeNameHint) { return Resolve(schema, typeNameHint, false); } @@ -55,7 +55,7 @@ public override string Resolve(JsonSchema schema, bool isNullable, string typeNa /// Gets a value indicating whether the schema supports constructor conversion. /// The schema. /// The result. - public bool SupportsConstructorConversion(JsonSchema schema) + public bool SupportsConstructorConversion(JsonSchema? schema) { return schema?.ActualSchema.ResponsibleDiscriminatorObject == null; } @@ -73,7 +73,7 @@ protected override bool IsDefinitionTypeSchema(JsonSchema schema) return base.IsDefinitionTypeSchema(schema); } - private string Resolve(JsonSchema schema, string typeNameHint, bool addInterfacePrefix) + private string Resolve(JsonSchema schema, string? typeNameHint, bool addInterfacePrefix) { if (schema == null) { @@ -155,7 +155,7 @@ private string Resolve(JsonSchema schema, string typeNameHint, bool addInterface if (resolvedType != defaultType) { var keyType = Settings.TypeScriptVersion >= 2.1m ? prefix + resolvedType : defaultType; - if (keyType != defaultType && schema.DictionaryKey.ActualTypeSchema.IsEnumeration) + if (keyType != defaultType && schema.DictionaryKey?.ActualTypeSchema.IsEnumeration == true) { if (Settings.EnumStyle == TypeScriptEnumStyle.Enum) { @@ -177,7 +177,7 @@ private string Resolve(JsonSchema schema, string typeNameHint, bool addInterface if (Settings.UseLeafType && schema.DiscriminatorObject == null && - schema.ActualTypeSchema.DiscriminatorObject != null) + schema.ActualTypeSchema.ActualDiscriminatorObject != null) { var types = schema.ActualTypeSchema.ActualDiscriminatorObject.Mapping .Select(m => Resolve( @@ -193,7 +193,7 @@ private string Resolve(JsonSchema schema, string typeNameHint, bool addInterface GetOrGenerateTypeName(schema, typeNameHint); } - private string ResolveString(JsonSchema schema, string typeNameHint) + private string ResolveString(JsonSchema schema, string? typeNameHint) { // TODO: Make this more generic (see DataConversionGenerator.IsDate) if (Settings.DateTimeType == TypeScriptDateTimeType.Date) @@ -289,17 +289,17 @@ private string ResolveString(JsonSchema schema, string typeNameHint) return "string"; } - private string ResolveInteger(JsonSchema schema, string typeNameHint) + private string ResolveInteger(JsonSchema schema, string? typeNameHint) { return "number"; } - private string ResolveArrayOrTuple(JsonSchema schema, string typeNameHint, bool addInterfacePrefix) + private string ResolveArrayOrTuple(JsonSchema schema, string? typeNameHint, bool addInterfacePrefix) { if (schema.Item != null) { - var isObject = schema.Item?.ActualSchema.Type.IsObject() == true; - var isDictionary = schema.Item?.ActualSchema.IsDictionary == true; + var isObject = schema.Item.ActualSchema.Type.IsObject() == true; + var isDictionary = schema.Item.ActualSchema.IsDictionary == true; var prefix = addInterfacePrefix && SupportsConstructorConversion(schema.Item) && isObject && !isDictionary ? "I" : ""; if (Settings.UseLeafType) @@ -340,7 +340,7 @@ private string ResolveArrayOrTuple(JsonSchema schema, string typeNameHint, bool private string GetNullableItemType(JsonSchema schema, string itemType) { - if (Settings.SupportsStrictNullChecks && schema.Item.IsNullable(Settings.SchemaType)) + if (Settings.SupportsStrictNullChecks && schema.Item?.IsNullable(Settings.SchemaType) == true) { return $"({itemType} | {Settings.NullValue.ToString().ToLowerInvariant()})"; } diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs index 390d00a7d..d6408c9b6 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs @@ -35,9 +35,9 @@ public TypeScriptValueGenerator(TypeScriptGeneratorSettings settings) /// The type name hint. /// The type resolver. /// The enum default value. - protected override string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string typeNameHint, TypeResolverBase typeResolver) + protected override string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string? typeNameHint, TypeResolverBase typeResolver) { - if (schema?.Default is not null && + if (schema.Default is not null && typeResolver is TypeScriptTypeResolver { Settings.EnumStyle: TypeScriptEnumStyle.StringLiteral }) { return GetDefaultAsStringLiteral(schema); @@ -54,14 +54,15 @@ protected override string GetEnumDefaultValue(JsonSchema schema, JsonSchema actu /// if set to true uses the default value from the schema if available. /// The type resolver. /// The code. - public override string GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) + public override string? GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string? typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) { var value = base.GetDefaultValue(schema, allowsNull, targetType, typeNameHint, useSchemaDefault, typeResolver); if (value == null) { if (schema.Default != null && useSchemaDefault) { - if (schema.Type.IsString() && + if (schema.Type.IsString() && + schema.Format is not null && _supportedFormatStrings.Contains(schema.Format)) { return GetDefaultAsStringLiteral(schema); @@ -98,7 +99,7 @@ public override string GetDefaultValue(JsonSchema schema, bool allowsNull, strin /// The value to convert. /// Optional schema format /// The TypeScript number literal. - public override string GetNumericValue(JsonObjectType type, object value, string format) + public override string GetNumericValue(JsonObjectType type, object value, string? format) { return ConvertNumberToString(value); } diff --git a/src/NJsonSchema.CodeGeneration/CodeArtifact.cs b/src/NJsonSchema.CodeGeneration/CodeArtifact.cs index a5a08f0b9..121988b53 100644 --- a/src/NJsonSchema.CodeGeneration/CodeArtifact.cs +++ b/src/NJsonSchema.CodeGeneration/CodeArtifact.cs @@ -31,7 +31,7 @@ public CodeArtifact(string typeName, CodeArtifactType type, CodeArtifactLanguage /// The category. /// The template to render the code. public CodeArtifact(string typeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, ITemplate template) - : this(typeName, null, type, language, category, template?.Render()) + : this(typeName, null, type, language, category, template.Render()) { } @@ -42,8 +42,8 @@ public CodeArtifact(string typeName, CodeArtifactType type, CodeArtifactLanguage /// The artifact language. /// The category. /// The template to render the code. - public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, ITemplate template) - : this(typeName, baseTypeName, type, language, category, template?.Render()) + public CodeArtifact(string typeName, string? baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, ITemplate template) + : this(typeName, baseTypeName, type, language, category, template.Render()) { } @@ -54,7 +54,7 @@ public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, /// The artifact language. /// The category. /// The code. - public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, string code) + public CodeArtifact(string typeName, string? baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, string code) { if (typeName == baseTypeName) { @@ -74,7 +74,7 @@ public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, public string TypeName { get; } /// Gets the name of the base type (i.e. the name of the inherited class). - public string BaseTypeName { get; } + public string? BaseTypeName { get; } /// Gets the artifact type. public CodeArtifactType Type { get; } diff --git a/src/NJsonSchema.CodeGeneration/CodeArtifactExtensions.cs b/src/NJsonSchema.CodeGeneration/CodeArtifactExtensions.cs index 63f3f3d1d..ddc19fc96 100644 --- a/src/NJsonSchema.CodeGeneration/CodeArtifactExtensions.cs +++ b/src/NJsonSchema.CodeGeneration/CodeArtifactExtensions.cs @@ -61,7 +61,7 @@ public static IEnumerable OrderByBaseDependency(this IEnumerableThe code generator settings base. - public class CodeGeneratorSettingsBase + public abstract class CodeGeneratorSettingsBase { /// Initializes a new instance of the class. +#pragma warning disable CS8618 public CodeGeneratorSettingsBase() +#pragma warning restore CS8618 { GenerateDefaultValues = true; ExcludedTypeNames = Array.Empty(); @@ -47,7 +49,7 @@ public CodeGeneratorSettingsBase() public ITemplateFactory TemplateFactory { get; set; } /// Gets or sets the template directory path. - public string TemplateDirectory { get; set; } + public string? TemplateDirectory { get; set; } /// Gets or sets the output language specific value generator. [JsonIgnore] diff --git a/src/NJsonSchema.CodeGeneration/DefaultEnumNameGenerator.cs b/src/NJsonSchema.CodeGeneration/DefaultEnumNameGenerator.cs index d5266e34d..02813c41c 100644 --- a/src/NJsonSchema.CodeGeneration/DefaultEnumNameGenerator.cs +++ b/src/NJsonSchema.CodeGeneration/DefaultEnumNameGenerator.cs @@ -22,7 +22,7 @@ public class DefaultEnumNameGenerator : IEnumNameGenerator /// The value. /// The schema. /// The enumeration name. - public string Generate(int index, string name, object value, JsonSchema schema) + public string Generate(int index, string? name, object? value, JsonSchema schema) { if (string.IsNullOrEmpty(name)) { @@ -54,7 +54,7 @@ public string Generate(int index, string name, object value, JsonSchema schema) break; } - if (name.StartsWith("-")) + if (name!.StartsWith("-")) { name = "Minus" + name.Substring(1); } diff --git a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs index 9fe46d433..348ccdb9c 100644 --- a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs +++ b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs @@ -170,7 +170,7 @@ public LiquidTemplate( public string Render() { var childScope = false; - TemplateContext templateContext = null; + TemplateContext? templateContext = null; try { @@ -253,7 +253,7 @@ public string Render() { if (childScope) { - templateContext.ReleaseScope(); + templateContext?.ReleaseScope(); } } } diff --git a/src/NJsonSchema.CodeGeneration/ExtensionCode.cs b/src/NJsonSchema.CodeGeneration/ExtensionCode.cs index 896c48d59..cbcba205d 100644 --- a/src/NJsonSchema.CodeGeneration/ExtensionCode.cs +++ b/src/NJsonSchema.CodeGeneration/ExtensionCode.cs @@ -25,7 +25,7 @@ public abstract class ExtensionCode public string TopCode { get; protected set; } = string.Empty; /// Gets the extension code which is appended at the end of the generated code. - public string BottomCode { get; protected set; } + public string? BottomCode { get; protected set; } /// Gets the body of the extension class. /// The class name. diff --git a/src/NJsonSchema.CodeGeneration/GeneratorBase.cs b/src/NJsonSchema.CodeGeneration/GeneratorBase.cs index 9b23c8a55..f5e915b6e 100644 --- a/src/NJsonSchema.CodeGeneration/GeneratorBase.cs +++ b/src/NJsonSchema.CodeGeneration/GeneratorBase.cs @@ -52,7 +52,7 @@ public string GenerateFile() /// The schema /// The type name hint. /// The code. - public IEnumerable GenerateTypes(JsonSchema schema, string typeNameHint) + public IEnumerable GenerateTypes(JsonSchema schema, string? typeNameHint) { _resolver.Resolve(schema, false, typeNameHint); // register root type return GenerateTypes(); @@ -60,7 +60,7 @@ public IEnumerable GenerateTypes(JsonSchema schema, string typeNam /// Generates the the whole file containing all needed types. /// The code - public string GenerateFile(JsonSchema schema, string typeNameHint) + public string GenerateFile(JsonSchema schema, string? typeNameHint) { var artifacts = GenerateTypes(schema, typeNameHint); return GenerateFile(artifacts); diff --git a/src/NJsonSchema.CodeGeneration/IEnumNameGenerator.cs b/src/NJsonSchema.CodeGeneration/IEnumNameGenerator.cs index c7c28a3e4..e78ad0e0c 100644 --- a/src/NJsonSchema.CodeGeneration/IEnumNameGenerator.cs +++ b/src/NJsonSchema.CodeGeneration/IEnumNameGenerator.cs @@ -17,6 +17,6 @@ public interface IEnumNameGenerator /// The value. /// The schema. /// The enumeration name. - string Generate(int index, string name, object value, JsonSchema schema); + string Generate(int index, string? name, object? value, JsonSchema schema); } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs b/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs index 2293ced00..aa567f6ff 100644 --- a/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs +++ b/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs @@ -18,7 +18,7 @@ public static class JsonSchemaGraphUtilities /// The schema. /// The root object. /// - public static IDictionary GetDerivedSchemas(this JsonSchema schema, object rootObject) + public static IDictionary GetDerivedSchemas(this JsonSchema schema, object rootObject) { var visitor = new DerivedSchemaVisitor(schema); visitor.Visit(rootObject); @@ -29,14 +29,14 @@ private sealed class DerivedSchemaVisitor : JsonSchemaVisitorBase { private readonly JsonSchema _baseSchema; - public Dictionary DerivedSchemas { get; } = new Dictionary(); + public Dictionary DerivedSchemas { get; } = new Dictionary(); public DerivedSchemaVisitor(JsonSchema baseSchema) { _baseSchema = baseSchema; } - protected override JsonSchema VisitSchema(JsonSchema schema, string path, string typeNameHint) + protected override JsonSchema VisitSchema(JsonSchema schema, string path, string? typeNameHint) { if (schema.Inherits(_baseSchema) && _baseSchema != schema) { diff --git a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs index 1fc949eca..14bcdcfb5 100644 --- a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs +++ b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs @@ -28,7 +28,7 @@ protected ClassTemplateModelBase(TypeResolverBase resolver, JsonSchema schema, o _rootObject = rootObject; _resolver = resolver; - SchemaTitle = _schema?.Title; + SchemaTitle = _schema.Title; } /// Gets the class. @@ -37,7 +37,7 @@ protected ClassTemplateModelBase(TypeResolverBase resolver, JsonSchema schema, o /// /// Gets the original title of the class (schema title). /// - public string SchemaTitle { get; } + public string? SchemaTitle { get; } /// Gets a value indicating whether this class represents a JSON object with fixed amount of properties. public bool IsObject => _schema.ActualTypeSchema.IsObject; @@ -46,18 +46,19 @@ protected ClassTemplateModelBase(TypeResolverBase resolver, JsonSchema schema, o public bool IsAbstract => _schema.ActualTypeSchema.IsAbstract; /// Gets the property extension data. - public IDictionary ExtensionData => _schema.ExtensionData; + public IDictionary? ExtensionData => _schema.ExtensionData; /// Gets the derived class names (discriminator key/type name). public ICollection DerivedClasses => _schema .GetDerivedSchemas(_rootObject) - .Select(p => new DerivedClassModel(p.Value, p.Key, _schema.ActualSchema.ResponsibleDiscriminatorObject, _resolver)) + .Where(p => _schema.ActualSchema.ResponsibleDiscriminatorObject != null) + .Select(p => new DerivedClassModel(p.Value!, p.Key, _schema.ActualSchema.ResponsibleDiscriminatorObject!, _resolver)) .ToList(); /// The model of a derived class. public class DerivedClassModel { - internal DerivedClassModel(string typeName, JsonSchema schema, OpenApiDiscriminator discriminator, TypeResolverBase resolver) + internal DerivedClassModel(string? typeName, JsonSchema schema, OpenApiDiscriminator discriminator, TypeResolverBase resolver) { var mapping = discriminator.Mapping.SingleOrDefault(m => m.Value.ActualTypeSchema == schema.ActualTypeSchema); @@ -66,7 +67,7 @@ internal DerivedClassModel(string typeName, JsonSchema schema, OpenApiDiscrimina Discriminator = mapping.Value != null ? mapping.Key : - !string.IsNullOrEmpty(typeName) ? typeName : + !string.IsNullOrEmpty(typeName) ? typeName! : ClassName; } diff --git a/src/NJsonSchema.CodeGeneration/Models/EnumerationItemModel.cs b/src/NJsonSchema.CodeGeneration/Models/EnumerationItemModel.cs index e2b59676a..4910aa7ac 100644 --- a/src/NJsonSchema.CodeGeneration/Models/EnumerationItemModel.cs +++ b/src/NJsonSchema.CodeGeneration/Models/EnumerationItemModel.cs @@ -12,15 +12,15 @@ namespace NJsonSchema.CodeGeneration.Models public class EnumerationItemModel { /// Gets or sets the name. - public string Name { get; set; } + public required string Name { get; set; } /// Gets or sets the value. - public string Value { get; set; } + public required string Value { get; set; } /// Gets or sets the internal value (e.g. the underlying/system value). - public string InternalValue { get; set; } + public string? InternalValue { get; set; } /// Gets or sets the internal flag value (e.g. the underlying/system value). - public string InternalFlagValue { get; set; } + public string? InternalFlagValue { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs index ec7701968..aabb4addf 100644 --- a/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs +++ b/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs @@ -48,7 +48,7 @@ protected PropertyModelBase( public bool HasDefaultValue => !string.IsNullOrEmpty(DefaultValue); /// Gets the default value as string. - public string DefaultValue => ValueGenerator.GetDefaultValue(_property, + public string? DefaultValue => ValueGenerator.GetDefaultValue(_property, _property.IsNullable(_settings.SchemaType), Type, _property.Name, _settings.GenerateDefaultValues, _typeResolver); /// Gets the name of the property. @@ -68,10 +68,10 @@ protected PropertyModelBase( _property.ActualTypeSchema.Item.ActualSchema.Type.IsString(); /// Gets the property extension data. - public IDictionary ExtensionData => _property.ExtensionData; + public IDictionary? ExtensionData => _property.ExtensionData; /// Gets the JSON Schema format property. - public string Format => _property.ActualSchema.Format; + public string? Format => _property.ActualSchema.Format; /// Gets the type name hint for the property. protected string GetTypeNameHint() diff --git a/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs b/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs index e95e5967b..c8d370aeb 100644 --- a/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs +++ b/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs @@ -32,7 +32,7 @@ protected TypeResolverBase(CodeGeneratorSettingsBase settings) /// The schema. /// The type name hint. /// The type name. - public string TryResolve(JsonSchema schema, string typeNameHint) + public string? TryResolve(JsonSchema? schema, string? typeNameHint) { return schema != null ? Resolve(schema, false, typeNameHint) : null; } @@ -42,13 +42,13 @@ public string TryResolve(JsonSchema schema, string typeNameHint) /// Specifies whether the given type usage is nullable. /// The type name hint to use when generating the type and the type name is missing. /// The type name. - public abstract string Resolve(JsonSchema schema, bool isNullable, string typeNameHint); + public abstract string Resolve(JsonSchema schema, bool isNullable, string? typeNameHint); /// Gets or generates the type name for the given schema. /// The schema. /// The type name hint. /// The type name. - public virtual string GetOrGenerateTypeName(JsonSchema schema, string typeNameHint) + public virtual string GetOrGenerateTypeName(JsonSchema schema, string? typeNameHint) { schema = RemoveNullability(schema).ActualSchema; diff --git a/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs b/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs index 7adf36fe6..6b632c951 100644 --- a/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs +++ b/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs @@ -48,7 +48,7 @@ protected ValueGeneratorBase(CodeGeneratorSettingsBase settings) /// if set to true uses the default value from the schema if available. /// The type resolver. /// The code. - public virtual string GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) + public virtual string? GetDefaultValue(JsonSchema schema, bool allowsNull, string targetType, string? typeNameHint, bool useSchemaDefault, TypeResolverBase typeResolver) { if (schema.Default == null || !useSchemaDefault) { @@ -61,7 +61,7 @@ public virtual string GetDefaultValue(JsonSchema schema, bool allowsNull, string return GetEnumDefaultValue(schema, actualSchema, typeNameHint, typeResolver); } - if (schema.Type.IsString() && _unsupportedFormatStrings.Contains(schema.Format) == false) + if (schema.Type.IsString() && (schema.Format == null || _unsupportedFormatStrings.Contains(schema.Format) == false)) { return GetDefaultAsStringLiteral(schema); } @@ -86,7 +86,7 @@ public virtual string GetDefaultValue(JsonSchema schema, bool allowsNull, string /// The value to convert. /// Optional schema format /// The number literal. - public abstract string GetNumericValue(JsonObjectType type, object value, string format); + public abstract string GetNumericValue(JsonObjectType type, object value, string? format); /// Gets the enum default value. /// The schema. @@ -94,14 +94,14 @@ public virtual string GetDefaultValue(JsonSchema schema, bool allowsNull, string /// The type name hint. /// The type resolver. /// The enum default value. - protected virtual string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string typeNameHint, TypeResolverBase typeResolver) + protected virtual string GetEnumDefaultValue(JsonSchema schema, JsonSchema actualSchema, string? typeNameHint, TypeResolverBase typeResolver) { var typeName = typeResolver.Resolve(actualSchema, false, typeNameHint); var index = actualSchema.Enumeration.ToList().IndexOf(schema.Default); var enumName = index >= 0 && actualSchema.EnumerationNames?.Count > index ? actualSchema.EnumerationNames.ElementAt(index) - : schema.Default.ToString(); + : schema.Default?.ToString(); return typeName.Trim('?') + "." + _settings.EnumNameGenerator.Generate(index, enumName, schema.Default, actualSchema); } @@ -111,7 +111,7 @@ protected virtual string GetEnumDefaultValue(JsonSchema schema, JsonSchema actua /// The string literal. protected string GetDefaultAsStringLiteral(JsonSchema schema) { - return "\"" + ConversionUtilities.ConvertToStringLiteral(schema.Default.ToString()) + "\""; + return "\"" + ConversionUtilities.ConvertToStringLiteral(schema.Default?.ToString() ?? string.Empty) + "\""; } /// Converts a number to its string representation. @@ -179,7 +179,7 @@ protected string ConvertNumberToString(object value) return (string)value; } - return null; + return value.ToString(); } } } diff --git a/src/NJsonSchema.Demo/NJsonSchema.Demo.csproj b/src/NJsonSchema.Demo/NJsonSchema.Demo.csproj index 123874202..76eb407fc 100644 --- a/src/NJsonSchema.Demo/NJsonSchema.Demo.csproj +++ b/src/NJsonSchema.Demo/NJsonSchema.Demo.csproj @@ -1,21 +1,22 @@  - - net6.0 - false - true - - Exe - - + + net6.0 + false + true + + Exe + + disable + - - - - + + + + - - - + + + diff --git a/src/NJsonSchema.NewtonsoftJson.Tests/NJsonSchema.NewtonsoftJson.Tests.csproj b/src/NJsonSchema.NewtonsoftJson.Tests/NJsonSchema.NewtonsoftJson.Tests.csproj index ad9ffb883..822b53a07 100644 --- a/src/NJsonSchema.NewtonsoftJson.Tests/NJsonSchema.NewtonsoftJson.Tests.csproj +++ b/src/NJsonSchema.NewtonsoftJson.Tests/NJsonSchema.NewtonsoftJson.Tests.csproj @@ -1,9 +1,10 @@ - + net6.0;net462 false false + disable diff --git a/src/NJsonSchema.NewtonsoftJson/Converters/JsonExceptionConverter.cs b/src/NJsonSchema.NewtonsoftJson/Converters/JsonExceptionConverter.cs index b4ee2779a..4e0fe72a3 100644 --- a/src/NJsonSchema.NewtonsoftJson/Converters/JsonExceptionConverter.cs +++ b/src/NJsonSchema.NewtonsoftJson/Converters/JsonExceptionConverter.cs @@ -46,7 +46,7 @@ public JsonExceptionConverter(bool hideStackTrace, IDictionary /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { var exception = value as Exception; if (exception != null) @@ -65,13 +65,16 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } }; - foreach (var property in GetExceptionProperties(value.GetType())) + if (value is not null) { - var propertyValue = property.Key.GetValue(exception); - if (propertyValue != null) + foreach (var property in GetExceptionProperties(value.GetType())) { - jObject.AddFirst(new JProperty(resolver.GetResolvedPropertyName(property.Value), - JToken.FromObject(propertyValue, serializer))); + var propertyValue = property.Key.GetValue(exception); + if (propertyValue != null) + { + jObject.AddFirst(new JProperty(resolver.GetResolvedPropertyName(property.Value), + JToken.FromObject(propertyValue, serializer))); + } } } @@ -95,7 +98,7 @@ public override bool CanConvert(Type objectType) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jObject = serializer.Deserialize(reader); if (jObject == null) @@ -123,7 +126,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist resolver.IgnoreSerializableInterface = true; } - JToken token; + JToken? token; if (jObject.TryGetValue("discriminator", StringComparison.OrdinalIgnoreCase, out token)) { var discriminator = token.Value(); @@ -150,30 +153,33 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } var value = jObject.ToObject(objectType, newSerializer); - foreach (var property in GetExceptionProperties(value.GetType())) + if (value is not null) { - var jValue = jObject.GetValue(resolver.GetResolvedPropertyName(property.Value)); - var propertyValue = (object)jValue?.ToObject(property.Key.PropertyType); - if (property.Key.SetMethod != null) - { - property.Key.SetValue(value, propertyValue); - } - else + foreach (var property in GetExceptionProperties(value.GetType())) { - var fieldNameSuffix = property.Value.Substring(0, 1).ToLowerInvariant() + property.Value.Substring(1); - - field = GetField(objectType, "m_" + fieldNameSuffix); - if (field != null) + var jValue = jObject.GetValue(resolver.GetResolvedPropertyName(property.Value)); + var propertyValue = (object?)jValue?.ToObject(property.Key.PropertyType); + if (property.Key.SetMethod != null) { - field.SetValue(value, propertyValue); + property.Key.SetValue(value, propertyValue); } else { - field = GetField(objectType, "_" + fieldNameSuffix); + var fieldNameSuffix = property.Value.Substring(0, 1).ToLowerInvariant() + property.Value.Substring(1); + + field = GetField(objectType, "m_" + fieldNameSuffix); if (field != null) { field.SetValue(value, propertyValue); } + else + { + field = GetField(objectType, "_" + fieldNameSuffix); + if (field != null) + { + field.SetValue(value, propertyValue); + } + } } } } @@ -186,7 +192,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return value; } - private FieldInfo GetField(Type type, string fieldName) + private FieldInfo? GetField(Type type, string fieldName) { var typeInfo = type.GetTypeInfo(); var field = typeInfo.GetDeclaredField(fieldName); @@ -206,7 +212,8 @@ private IDictionary GetExceptionProperties(Type exceptionT var attribute = property.GetCustomAttribute(); var propertyName = attribute != null ? attribute.PropertyName : property.Name; - if (!new[] { "Message", "StackTrace", "Source", "InnerException", "Data", "TargetSite", "HelpLink", "HResult" }.Contains(propertyName)) + if (propertyName is not null && + !new[] { "Message", "StackTrace", "Source", "InnerException", "Data", "TargetSite", "HelpLink", "HResult" }.Contains(propertyName)) { result[property] = propertyName; } diff --git a/src/NJsonSchema.NewtonsoftJson/Converters/JsonInheritanceConverter.cs b/src/NJsonSchema.NewtonsoftJson/Converters/JsonInheritanceConverter.cs index 154e52ede..9b31a8dbc 100644 --- a/src/NJsonSchema.NewtonsoftJson/Converters/JsonInheritanceConverter.cs +++ b/src/NJsonSchema.NewtonsoftJson/Converters/JsonInheritanceConverter.cs @@ -23,7 +23,7 @@ public class JsonInheritanceConverter : JsonConverter /// Gets the default discriminiator name. public static string DefaultDiscriminatorName { get; } = "discriminator"; - private readonly Type _baseType; + private readonly Type? _baseType; private readonly string _discriminator; private readonly bool _readTypeProperty; @@ -81,15 +81,22 @@ public JsonInheritanceConverter(Type baseType, string discriminator) /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { try { _isWriting = true; - var jObject = JObject.FromObject(value, serializer); - jObject[_discriminator] = JToken.FromObject(GetDiscriminatorValue(value.GetType())); - writer.WriteToken(jObject.CreateReader()); + if (value is not null) + { + var jObject = JObject.FromObject(value, serializer); + jObject[_discriminator] = JToken.FromObject(GetDiscriminatorValue(value.GetType())); + writer.WriteToken(jObject.CreateReader()); + } + else + { + writer.WriteNull(); + } } finally { @@ -155,7 +162,7 @@ public override bool CanConvert(Type objectType) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jObject = serializer.Deserialize(reader); if (jObject == null) @@ -202,30 +209,33 @@ public virtual string GetDiscriminatorValue(Type type) /// The object (base) type. /// The discriminator value. /// - protected virtual Type GetDiscriminatorType(JObject jObject, Type objectType, string discriminatorValue) + protected virtual Type GetDiscriminatorType(JObject jObject, Type objectType, string? discriminatorValue) { - var jsonInheritanceAttributeSubtype = GetObjectSubtype(objectType, discriminatorValue); - if (jsonInheritanceAttributeSubtype != null) + if (discriminatorValue is not null) { - return jsonInheritanceAttributeSubtype; - } + var jsonInheritanceAttributeSubtype = GetObjectSubtype(objectType, discriminatorValue); + if (jsonInheritanceAttributeSubtype != null) + { + return jsonInheritanceAttributeSubtype; + } - if (objectType.Name == discriminatorValue) - { - return objectType; - } + if (objectType.Name == discriminatorValue) + { + return objectType; + } - var knownTypeAttributesSubtype = GetSubtypeFromKnownTypeAttributes(objectType, discriminatorValue); - if (knownTypeAttributesSubtype != null) - { - return knownTypeAttributesSubtype; - } + var knownTypeAttributesSubtype = GetSubtypeFromKnownTypeAttributes(objectType, discriminatorValue); + if (knownTypeAttributesSubtype != null) + { + return knownTypeAttributesSubtype; + } - var typeName = objectType.Namespace + "." + discriminatorValue; - var subtype = objectType.GetTypeInfo().Assembly.GetType(typeName); - if (subtype != null) - { - return subtype; + var typeName = objectType.Namespace + "." + discriminatorValue; + var subtype = objectType.GetTypeInfo().Assembly.GetType(typeName); + if (subtype != null) + { + return subtype; + } } if (_readTypeProperty) @@ -240,7 +250,7 @@ protected virtual Type GetDiscriminatorType(JObject jObject, Type objectType, st throw new InvalidOperationException("Could not find subtype of '" + objectType.Name + "' with discriminator '" + discriminatorValue + "'."); } - private Type GetSubtypeFromKnownTypeAttributes(Type objectType, string discriminator) + private Type? GetSubtypeFromKnownTypeAttributes(Type objectType, string discriminator) { var type = objectType; do @@ -276,7 +286,7 @@ private Type GetSubtypeFromKnownTypeAttributes(Type objectType, string discrimin return null; } - private static Type GetObjectSubtype(Type baseType, string discriminatorName) + private static Type? GetObjectSubtype(Type baseType, string discriminatorName) { var jsonInheritanceAttributes = baseType .GetTypeInfo() @@ -286,7 +296,7 @@ private static Type GetObjectSubtype(Type baseType, string discriminatorName) return jsonInheritanceAttributes.SingleOrDefault(a => a.Key == discriminatorName)?.Type; } - private static string GetSubtypeDiscriminator(Type objectType) + private static string? GetSubtypeDiscriminator(Type objectType) { var jsonInheritanceAttributes = objectType .GetTypeInfo() diff --git a/src/NJsonSchema.NewtonsoftJson/Converters/JsonReferenceConverter.cs b/src/NJsonSchema.NewtonsoftJson/Converters/JsonReferenceConverter.cs index fd85d4962..5a91833c7 100644 --- a/src/NJsonSchema.NewtonsoftJson/Converters/JsonReferenceConverter.cs +++ b/src/NJsonSchema.NewtonsoftJson/Converters/JsonReferenceConverter.cs @@ -36,7 +36,7 @@ public override bool CanConvert(Type objectType) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { return serializer.Deserialize(reader, objectType); } @@ -45,9 +45,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - JsonSchemaReferenceUtilities.UpdateSchemaReferencePaths(value, false, serializer.ContractResolver); + if (value is not null) + { + JsonSchemaReferenceUtilities.UpdateSchemaReferencePaths(value, false, serializer.ContractResolver); + } + try { _isWriting = true; diff --git a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs index ed880c9f4..7f2f3259c 100644 --- a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs +++ b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs @@ -17,6 +17,7 @@ using System.Reflection; using NJsonSchema; using NJsonSchema.Generation; +using System.Collections.Generic; namespace NJsonSchema.NewtonsoftJson.Generation { @@ -52,21 +53,21 @@ public override bool IsNullable(ContextualType contextualType, ReferenceTypeNull /// public override bool IsStringEnum(ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings) { - var hasGlobalStringEnumConverter = settings.SerializerSettings.Converters.OfType().Any(); + var hasGlobalStringEnumConverter = settings.SerializerSettings?.Converters.OfType().Any() == true; return hasGlobalStringEnumConverter || base.IsStringEnum(contextualType, settings); } /// public override string ConvertEnumValue(object value, NewtonsoftJsonSchemaGeneratorSettings settings) { - var converters = settings.SerializerSettings.Converters.ToList(); + var converters = settings.SerializerSettings?.Converters.ToList() ?? new List(); if (!converters.OfType().Any()) { converters.Add(new StringEnumConverter()); } var json = JsonConvert.SerializeObject(value, Formatting.None, converters.ToArray()); - var enumString = JsonConvert.DeserializeObject(json); + var enumString = JsonConvert.DeserializeObject(json)!; return enumString; } @@ -97,7 +98,7 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex bool shouldSerialize; try { - shouldSerialize = jsonProperty.ShouldSerialize?.Invoke(null) != false; + shouldSerialize = jsonProperty.ShouldSerialize?.Invoke(null!) != false; } catch { @@ -196,7 +197,7 @@ private void LoadPropertyOrField(JsonProperty jsonProperty, ContextualAccessorIn } } - private string GetPropertyName(JsonProperty jsonProperty, ContextualAccessorInfo accessorInfo, NewtonsoftJsonSchemaGeneratorSettings settings) + private string GetPropertyName(JsonProperty? jsonProperty, ContextualAccessorInfo accessorInfo, NewtonsoftJsonSchemaGeneratorSettings settings) { if (jsonProperty?.PropertyName != null) { diff --git a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonSchemaGeneratorSettings.cs b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonSchemaGeneratorSettings.cs index d7cc9630c..f0f42731c 100644 --- a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonSchemaGeneratorSettings.cs +++ b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonSchemaGeneratorSettings.cs @@ -18,15 +18,15 @@ namespace NJsonSchema.NewtonsoftJson.Generation /// public class NewtonsoftJsonSchemaGeneratorSettings : JsonSchemaGeneratorSettings { - private Dictionary _cachedContracts = new Dictionary(); + private Dictionary _cachedContracts = new Dictionary(); private JsonSerializerSettings _serializerSettings; /// Initializes a new instance of the class. - public NewtonsoftJsonSchemaGeneratorSettings() + public NewtonsoftJsonSchemaGeneratorSettings() + : base(new NewtonsoftJsonReflectionService()) { - ReflectionService = new NewtonsoftJsonReflectionService(); - SerializerSettings = new JsonSerializerSettings(); + _serializerSettings = new JsonSerializerSettings(); } /// Gets or sets the Newtonsoft JSON serializer settings. @@ -44,12 +44,12 @@ public JsonSerializerSettings SerializerSettings /// The contract resolver. /// A setting is misconfigured. [JsonIgnore] - public IContractResolver ActualContractResolver => SerializerSettings.ContractResolver ?? new DefaultContractResolver(); + public IContractResolver ActualContractResolver => SerializerSettings?.ContractResolver ?? new DefaultContractResolver(); /// Gets the contract for the given type. /// The type. /// The contract. - public JsonContract ResolveContract(Type type) + public JsonContract? ResolveContract(Type type) { var key = type.FullName; if (key == null) diff --git a/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs b/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs index 9fc1f6392..84fb33726 100644 --- a/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs +++ b/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs @@ -98,9 +98,9 @@ private async Task When_converting_smth_then_items_must_correctly_be_loaded(stri var property = schema.Properties[propertyName]; Assert.Equal(JsonObjectType.Array | JsonObjectType.Null, property.Type); - Assert.Equal(JsonObjectType.Object, property.ActualSchema.Item.ActualSchema.Type); + Assert.Equal(JsonObjectType.Object, property.ActualSchema.Item?.ActualSchema.Type); Assert.Contains(schema.Definitions, d => d.Key == "MySubtype"); - Assert.Equal(JsonObjectType.String | JsonObjectType.Null, property.ActualSchema.Item.ActualSchema.Properties["Id"].Type); + Assert.Equal(JsonObjectType.String | JsonObjectType.Null, property.ActualSchema.Item?.ActualSchema.Properties["Id"].Type); } } } diff --git a/src/NJsonSchema.Tests/NJsonSchema.Tests.csproj b/src/NJsonSchema.Tests/NJsonSchema.Tests.csproj index a1b548af4..68985ba59 100644 --- a/src/NJsonSchema.Tests/NJsonSchema.Tests.csproj +++ b/src/NJsonSchema.Tests/NJsonSchema.Tests.csproj @@ -1,47 +1,48 @@  - - net7.0;net462 - false - false - - - - bin\Debug\$(TargetFramework)\NJsonSchema.Tests.xml - $(NoWarn),618,1587,1998,1591 - - - - - - - - - - - - - - - - - - - - - - - True - True - AttributeGenerationTestsResources.resx - - - - - - PublicResXFileCodeGenerator - AttributeGenerationTestsResources.Designer.cs - - + + net7.0;net462 + false + false + disable + + + + bin\Debug\$(TargetFramework)\NJsonSchema.Tests.xml + $(NoWarn),618,1587,1998,1591 + + + + + + + + + + + + + + + + + + + + + + + True + True + AttributeGenerationTestsResources.resx + + + + + + PublicResXFileCodeGenerator + AttributeGenerationTestsResources.Designer.cs + + diff --git a/src/NJsonSchema.Yaml.Tests/NJsonSchema.Yaml.Tests.csproj b/src/NJsonSchema.Yaml.Tests/NJsonSchema.Yaml.Tests.csproj index 5ad2e4d9a..24f1b54ff 100644 --- a/src/NJsonSchema.Yaml.Tests/NJsonSchema.Yaml.Tests.csproj +++ b/src/NJsonSchema.Yaml.Tests/NJsonSchema.Yaml.Tests.csproj @@ -1,27 +1,28 @@  - - net6.0;net462 - false - false - + + net6.0;net462 + false + false + disable + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + \ No newline at end of file diff --git a/src/NJsonSchema.Yaml.Tests/References/YamlReferencesTests.cs b/src/NJsonSchema.Yaml.Tests/References/YamlReferencesTests.cs index cae414300..c3972931e 100644 --- a/src/NJsonSchema.Yaml.Tests/References/YamlReferencesTests.cs +++ b/src/NJsonSchema.Yaml.Tests/References/YamlReferencesTests.cs @@ -33,7 +33,7 @@ public async Task When_yaml_schema_has_references_it_works(string relativePath, Assert.Equal(documentPath, schema.Definitions["collection"].DocumentPath); } - [Theory] + [Theory(Skip = "Currently not compatible")] [InlineData("/References/YamlReferencesTest/yaml_spec_with_yaml_schema_refs.yaml", "/custom-queries", "Content-Language")] public async Task When_yaml_OpenAPI_spec_has_external_schema_refs_they_are_resolved(string relativePath, string docPath, string header) { @@ -78,7 +78,7 @@ public async Task When_yaml_OpenAPI_spec_is__served_with_gzip_compression__it_wo Assert.Equal(expectedBaseUrl, doc.BaseUrl); } - [Theory] + [Theory(Skip = "Currently not compatible")] [InlineData("/References/YamlReferencesTest/subdir_spec/yaml_spec_with_yaml_schema_with_relative_subdir_refs.yaml")] public async Task When_yaml_OpenAPI_spec_has_relative_external_schema_refs_in_subdirs__they_are_resolved(string relativePath) { diff --git a/src/NJsonSchema.Yaml/JsonSchemaYaml.cs b/src/NJsonSchema.Yaml/JsonSchemaYaml.cs index 55732eadb..2bcf9b96a 100644 --- a/src/NJsonSchema.Yaml/JsonSchemaYaml.cs +++ b/src/NJsonSchema.Yaml/JsonSchemaYaml.cs @@ -34,7 +34,7 @@ public static async Task FromYamlAsync(string data) /// The JSON string. /// The document path (URL or file path) for resolving relative document references. /// The JSON Schema. - public static async Task FromYamlAsync(string data, string documentPath) + public static async Task FromYamlAsync(string data, string? documentPath) { var factory = JsonAndYamlReferenceResolver.CreateJsonAndYamlReferenceResolverFactory(new DefaultTypeNameGenerator()); return await FromYamlAsync(data, documentPath, factory).ConfigureAwait(false); @@ -45,7 +45,7 @@ public static async Task FromYamlAsync(string data, string documentP /// The document path (URL or file path) for resolving relative document references. /// The JSON reference resolver factory. /// The JSON Schema. - public static async Task FromYamlAsync(string data, string documentPath, Func referenceResolverFactory, CancellationToken cancellationToken = default) + public static async Task FromYamlAsync(string data, string? documentPath, Func referenceResolverFactory, CancellationToken cancellationToken = default) { var deserializer = new DeserializerBuilder().Build(); var yamlObject = deserializer.Deserialize(new StringReader(data)); @@ -61,9 +61,9 @@ public static async Task FromYamlAsync(string data, string documentP /// The YAML string. public static string ToYaml(this JsonSchema document) { - var json = document.ToJson(); + var json = document.ToJson()!; var expConverter = new ExpandoObjectConverter(); - dynamic deserializedObject = JsonConvert.DeserializeObject(json, expConverter); + dynamic? deserializedObject = JsonConvert.DeserializeObject(json, expConverter); var serializer = new Serializer(); return serializer.Serialize(deserializedObject); @@ -84,7 +84,7 @@ public static async Task FromFileAsync(string filePath) /// The . public static async Task FromFileAsync(string filePath, Func referenceResolverFactory, CancellationToken cancellationToken = default) { - var data = DynamicApis.FileReadAllText(filePath); + var data = File.ReadAllText(filePath); return await FromYamlAsync(data, filePath, referenceResolverFactory, cancellationToken).ConfigureAwait(false); } diff --git a/src/NJsonSchema/Annotations/JsonSchemaAttribute.cs b/src/NJsonSchema/Annotations/JsonSchemaAttribute.cs index 8ce094a48..651b33099 100644 --- a/src/NJsonSchema/Annotations/JsonSchemaAttribute.cs +++ b/src/NJsonSchema/Annotations/JsonSchemaAttribute.cs @@ -36,15 +36,15 @@ public JsonSchemaAttribute(JsonObjectType type) } /// Gets or sets the name identifier of the schema which is used as key in the 'definitions' list. - public string Name { get; set; } + public string? Name { get; set; } /// Gets the JSON Schema type (default: , i.e. derived from ). public JsonObjectType Type { get; private set; } /// Gets or sets the JSON format type (default: null, i.e. derived from ). - public string Format { get; set; } + public string? Format { get; set; } /// Gets or sets the array item type. - public Type ArrayItem { get; set; } + public Type? ArrayItem { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema/Annotations/JsonSchemaPatternPropertiesAttribute.cs b/src/NJsonSchema/Annotations/JsonSchemaPatternPropertiesAttribute.cs index f1a181e16..b2c4fc512 100644 --- a/src/NJsonSchema/Annotations/JsonSchemaPatternPropertiesAttribute.cs +++ b/src/NJsonSchema/Annotations/JsonSchemaPatternPropertiesAttribute.cs @@ -24,7 +24,7 @@ public JsonSchemaPatternPropertiesAttribute(string regularExpression) /// Initializes a new instance of the class. /// The pattern property regular expression. /// The pattern properties type. - public JsonSchemaPatternPropertiesAttribute(string regularExpression, Type type) + public JsonSchemaPatternPropertiesAttribute(string regularExpression, Type? type) { RegularExpression = regularExpression; Type = type; @@ -34,6 +34,6 @@ public JsonSchemaPatternPropertiesAttribute(string regularExpression, Type type) public string RegularExpression { get; } /// Gets the pattern properties type. - public Type Type { get; } + public Type? Type { get; } } } \ No newline at end of file diff --git a/src/NJsonSchema/Collections/ObservableCollectionExtensions.cs b/src/NJsonSchema/Collections/ObservableCollectionExtensions.cs index f9207dc21..7300470f2 100644 --- a/src/NJsonSchema/Collections/ObservableCollectionExtensions.cs +++ b/src/NJsonSchema/Collections/ObservableCollectionExtensions.cs @@ -40,7 +40,7 @@ public static T First(this ObservableCollection collection) } ThrowNoMatchingElement(); - return default; + return default!; } public static T First(this ObservableCollection collection, Func predicate) @@ -55,10 +55,10 @@ public static T First(this ObservableCollection collection, Func } ThrowNoMatchingElement(); - return default; + return default!; } - public static T FirstOrDefault(this ObservableCollection collection, Func predicate) where T : class + public static T? FirstOrDefault(this ObservableCollection collection, Func predicate) where T : class { for (var i = 0; i < collection.Count; ++i) { @@ -72,7 +72,7 @@ public static T FirstOrDefault(this ObservableCollection collection, Func< return null; } - public static T FirstOrDefault(this ObservableCollection collection) where T : class + public static T? FirstOrDefault(this ObservableCollection collection) where T : class { if (collection.Count > 0) { diff --git a/src/NJsonSchema/Collections/ObservableDictionary.cs b/src/NJsonSchema/Collections/ObservableDictionary.cs index 69bd2bb2e..fdcd8f4de 100644 --- a/src/NJsonSchema/Collections/ObservableDictionary.cs +++ b/src/NJsonSchema/Collections/ObservableDictionary.cs @@ -22,42 +22,43 @@ internal sealed class ObservableDictionary : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged, IDictionary, IReadOnlyDictionary + where TKey : notnull { - private Dictionary _dictionary; + private Dictionary _dictionary; /// Initializes a new instance of the class. public ObservableDictionary() { - _dictionary = new Dictionary(); + _dictionary = new Dictionary(); } /// Initializes a new instance of the class. /// The dictionary to initialize this dictionary. - public ObservableDictionary(IDictionary dictionary) + public ObservableDictionary(IDictionary dictionary) { - _dictionary = new Dictionary(dictionary); + _dictionary = new Dictionary(dictionary); } /// Initializes a new instance of the class. /// The comparer. public ObservableDictionary(IEqualityComparer comparer) { - _dictionary = new Dictionary(comparer); + _dictionary = new Dictionary(comparer); } /// Initializes a new instance of the class. /// The capacity. public ObservableDictionary(int capacity) { - _dictionary = new Dictionary(capacity); + _dictionary = new Dictionary(capacity); } /// Initializes a new instance of the class. /// The dictionary to initialize this dictionary. /// The comparer. - public ObservableDictionary(IDictionary dictionary, IEqualityComparer comparer) + public ObservableDictionary(IDictionary dictionary, IEqualityComparer comparer) { - _dictionary = new Dictionary(dictionary, comparer); + _dictionary = new Dictionary(dictionary, comparer); } /// Initializes a new instance of the class. @@ -65,12 +66,12 @@ public ObservableDictionary(IDictionary dictionary, IEqualityCompa /// The comparer. public ObservableDictionary(int capacity, IEqualityComparer comparer) { - _dictionary = new Dictionary(capacity, comparer); + _dictionary = new Dictionary(capacity, comparer); } /// Adds multiple key-value pairs the the dictionary. /// The key-value pairs. - public void AddRange(IDictionary items) + public void AddRange(IDictionary items) { if (items == null) { @@ -93,7 +94,7 @@ public void AddRange(IDictionary items) } else { - _dictionary = new Dictionary(items); + _dictionary = new Dictionary(items); } OnCollectionChanged(NotifyCollectionChangedAction.Add, items.ToArray()); @@ -104,9 +105,9 @@ public void AddRange(IDictionary items) /// The key. /// The value. /// If true and key already exists then an exception is thrown. - private void Insert(TKey key, TValue value, bool add) + private void Insert(TKey key, TValue? value, bool add) { - TValue item; + TValue? item; if (_dictionary.TryGetValue(key, out item)) { if (add) @@ -120,13 +121,13 @@ private void Insert(TKey key, TValue value, bool add) } _dictionary[key] = value; - OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair(key, value), - new KeyValuePair(key, item)); + OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair(key, value), + new KeyValuePair(key, item)); } else { _dictionary[key] = value; - OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair(key, value)); + OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair(key, value)); } } @@ -149,7 +150,7 @@ private void OnCollectionChanged() } } - private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair changedItem) + private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair changedItem) { OnPropertyChanged(); var copy = CollectionChanged; @@ -159,8 +160,8 @@ private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValueP } } - private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair newItem, - KeyValuePair oldItem) + private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair newItem, + KeyValuePair oldItem) { OnPropertyChanged(); var copy = CollectionChanged; @@ -215,7 +216,7 @@ public bool Remove(TKey key) throw new ArgumentNullException("key"); } - TValue value; + TValue? value; _dictionary.TryGetValue(key, out value); var removed = _dictionary.Remove(key); @@ -230,16 +231,16 @@ public bool Remove(TKey key) public bool TryGetValue(TKey key, out TValue value) { - return _dictionary.TryGetValue(key, out value); + return _dictionary.TryGetValue(key, out value!); } IEnumerable IReadOnlyDictionary.Keys => Keys; - public ICollection Values => _dictionary.Values; + public ICollection Values => _dictionary.Values!; public TValue this[TKey key] { - get => _dictionary[key]; + get => _dictionary[key]!; set => Insert(key, value, false); } @@ -252,9 +253,9 @@ public void Add(KeyValuePair item) Insert(item.Key, item.Value, true); } - void IDictionary.Add(object key, object value) + void IDictionary.Add(object key, object? value) { - Insert((TKey) key, (TValue) value, true); + Insert((TKey) key, (TValue?)value, true); } public void Clear() @@ -306,7 +307,7 @@ public void Remove(object key) public bool Contains(KeyValuePair item) { - return _dictionary.Contains(item); + return _dictionary!.Contains(item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) @@ -322,14 +323,14 @@ public void CopyTo(Array array, int index) public int Count => _dictionary.Count; public bool IsSynchronized { get; private set; } - public object SyncRoot { get; private set; } + public object SyncRoot { get; } = new object(); public bool IsReadOnly => ((IDictionary) _dictionary).IsReadOnly; - object IDictionary.this[object key] + object? IDictionary.this[object key] { get => this[(TKey) key]; - set => this[(TKey) key] = (TValue) value; + set => this[(TKey) key] = (TValue?)value!; } public bool Remove(KeyValuePair item) @@ -343,7 +344,7 @@ public bool Remove(KeyValuePair item) IEnumerator> IEnumerable>.GetEnumerator() => GetEnumerator(); - public Dictionary.Enumerator GetEnumerator() => _dictionary.GetEnumerator(); + public Dictionary.Enumerator GetEnumerator() => _dictionary.GetEnumerator(); #endregion @@ -358,13 +359,13 @@ IEnumerator IEnumerable.GetEnumerator() #region INotifyCollectionChanged interface - public event NotifyCollectionChangedEventHandler CollectionChanged; + public event NotifyCollectionChangedEventHandler? CollectionChanged; #endregion #region INotifyPropertyChanged interface - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; #endregion } diff --git a/src/NJsonSchema/CompilerFeatures.cs b/src/NJsonSchema/CompilerFeatures.cs new file mode 100644 index 000000000..d0b78f8b1 --- /dev/null +++ b/src/NJsonSchema/CompilerFeatures.cs @@ -0,0 +1,262 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// Source: https://raw.githubusercontent.com/dotnet/runtime/main/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +#if NETSTANDARD2_0 || NET462 +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// Specifies that a type has required members or that a member is required. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class RequiredMemberAttribute : Attribute + { } +} + +namespace System.Runtime.CompilerServices +{ + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class IsExternalInit + { } +} + +namespace System.Runtime.CompilerServices +{ + /// + /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied. + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + public sealed class CompilerFeatureRequiredAttribute : Attribute + { + /// + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + + /// + /// The name of the compiler feature. + /// + public string FeatureName { get; } + + /// + /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + /// + public bool IsOptional { get; init; } + + /// + /// The used for the ref structs C# feature. + /// + public const string RefStructs = nameof(RefStructs); + + /// + /// The used for the required members C# feature. + /// + public const string RequiredMembers = nameof(RequiredMembers); + } +} + +namespace System.Diagnostics.CodeAnalysis +{ +#if !NETSTANDARD2_1 + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class AllowNullAttribute : Attribute + { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DisallowNullAttribute : Attribute + { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullAttribute : Attribute + { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnAttribute : Attribute + { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +#endif + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} +#endif diff --git a/src/NJsonSchema/ConversionUtilities.cs b/src/NJsonSchema/ConversionUtilities.cs index dd1ae7e2d..1aa9fe006 100644 --- a/src/NJsonSchema/ConversionUtilities.cs +++ b/src/NJsonSchema/ConversionUtilities.cs @@ -167,9 +167,9 @@ public static string ConvertToCamelCase(string input) /// Trims white spaces from the text. /// The text. /// The updated text. - public static string TrimWhiteSpaces(string text) + public static string TrimWhiteSpaces(string? text) { - return text?.Trim(_whiteSpaceChars); + return text?.Trim(_whiteSpaceChars) ?? string.Empty; } private static readonly char[] _lineBreakTrimChars = { '\n', '\t', ' ' }; @@ -177,14 +177,14 @@ public static string TrimWhiteSpaces(string text) /// Removes the line breaks from the text. /// The text. /// The updated text. - public static string RemoveLineBreaks(string text) + public static string RemoveLineBreaks(string? text) { return text?.Replace("\r", "") .Replace("\n", " \n") .Replace("\n ", "\n") .Replace(" \n", " \n") .Replace("\n", "") - .Trim(_lineBreakTrimChars); + .Trim(_lineBreakTrimChars) ?? string.Empty; } /// Singularizes the given noun in plural. diff --git a/src/NJsonSchema/Converters/JsonInheritanceConverter.cs b/src/NJsonSchema/Converters/JsonInheritanceConverter.cs index 4b49c726d..bdd5b6d78 100644 --- a/src/NJsonSchema/Converters/JsonInheritanceConverter.cs +++ b/src/NJsonSchema/Converters/JsonInheritanceConverter.cs @@ -21,7 +21,7 @@ namespace NJsonSchema.Converters /// public class JsonInheritanceConverterAttribute : JsonConverterAttribute { - /// Gets the default discriminiator name. + /// Gets the default discriminator name. public static string DefaultDiscriminatorName { get; } = "discriminator"; /// @@ -40,7 +40,7 @@ public JsonInheritanceConverterAttribute(Type baseType, string discriminatorName } /// Defines the class as inheritance base class and adds a discriminator property to the serialized object. - public class JsonInheritanceConverter : JsonConverter + public class JsonInheritanceConverter : JsonConverter { /// Gets the list of additional known types. public static IDictionary AdditionalKnownTypes { get; } = new Dictionary(); @@ -65,7 +65,7 @@ public JsonInheritanceConverter(string discriminatorName) public virtual string DiscriminatorName => _discriminatorName; /// - public override TBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override TBase? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var document = JsonDocument.ParseValue(ref reader); var hasDiscriminator = document.RootElement.TryGetProperty(_discriminatorName, out var discriminator); @@ -77,31 +77,30 @@ public override TBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe document.RootElement.WriteTo(writer); } - return (TBase)JsonSerializer.Deserialize(bufferWriter.ToArray(), subtype, options); - - //var bufferWriter = new ArrayBufferWriter(); - //using (var writer = new Utf8JsonWriter(bufferWriter)) - //{ - // document.RootElement.WriteTo(writer); - //} - - //return (TBase)JsonSerializer.Deserialize(bufferWriter.WrittenSpan, subtype, options); + return (TBase?)JsonSerializer.Deserialize(bufferWriter.ToArray(), subtype, options)!; } /// - public override void Write(Utf8JsonWriter writer, TBase value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, TBase? value, JsonSerializerOptions options) { - writer.WriteStartObject(); - writer.WriteString(_discriminatorName, GetDiscriminatorValue(value.GetType())); + if (value is not null) + { + writer.WriteStartObject(); + writer.WriteString(_discriminatorName, GetDiscriminatorValue(value.GetType())); - var bytes = JsonSerializer.SerializeToUtf8Bytes((object)value, options); - var document = JsonDocument.Parse(bytes); - foreach (var property in document.RootElement.EnumerateObject()) + var bytes = JsonSerializer.SerializeToUtf8Bytes((object)value, options); + var document = JsonDocument.Parse(bytes); + foreach (var property in document.RootElement.EnumerateObject()) + { + property.WriteTo(writer); + } + + writer.WriteEndObject(); + } + else { - property.WriteTo(writer); + writer.WriteNullValue(); } - - writer.WriteEndObject(); } /// Gets the discriminator value for the given type. @@ -129,41 +128,44 @@ public virtual string GetDiscriminatorValue(Type type) /// The object (base) type. /// The discriminator value. /// - protected virtual Type GetDiscriminatorType(JsonElement jObject, Type objectType, string discriminatorValue) + protected virtual Type GetDiscriminatorType(JsonElement jObject, Type objectType, string? discriminatorValue) { - if (AdditionalKnownTypes.ContainsKey(discriminatorValue)) + if (discriminatorValue != null) { - return AdditionalKnownTypes[discriminatorValue]; - } + if (AdditionalKnownTypes.ContainsKey(discriminatorValue)) + { + return AdditionalKnownTypes[discriminatorValue]; + } - var jsonInheritanceAttributeSubtype = GetObjectSubtype(objectType, discriminatorValue); - if (jsonInheritanceAttributeSubtype != null) - { - return jsonInheritanceAttributeSubtype; - } + var jsonInheritanceAttributeSubtype = GetObjectSubtype(objectType, discriminatorValue); + if (jsonInheritanceAttributeSubtype != null) + { + return jsonInheritanceAttributeSubtype; + } - if (objectType.Name == discriminatorValue) - { - return objectType; - } + if (objectType.Name == discriminatorValue) + { + return objectType; + } - var knownTypeAttributesSubtype = GetSubtypeFromKnownTypeAttributes(objectType, discriminatorValue); - if (knownTypeAttributesSubtype != null) - { - return knownTypeAttributesSubtype; - } + var knownTypeAttributesSubtype = GetSubtypeFromKnownTypeAttributes(objectType, discriminatorValue); + if (knownTypeAttributesSubtype != null) + { + return knownTypeAttributesSubtype; + } - var typeName = objectType.Namespace + "." + discriminatorValue; - var subtype = objectType.GetTypeInfo().Assembly.GetType(typeName); - if (subtype != null) - { - return subtype; + var typeName = objectType.Namespace + "." + discriminatorValue; + var subtype = objectType.GetTypeInfo().Assembly.GetType(typeName); + if (subtype != null) + { + return subtype; + } } throw new InvalidOperationException("Could not find subtype of '" + objectType.Name + "' with discriminator '" + discriminatorValue + "'."); } - private static Type GetSubtypeFromKnownTypeAttributes(Type objectType, string discriminatorValue) + private static Type? GetSubtypeFromKnownTypeAttributes(Type objectType, string discriminatorValue) { var type = objectType; do @@ -184,12 +186,15 @@ private static Type GetSubtypeFromKnownTypeAttributes(Type objectType, string di var method = type.GetRuntimeMethod((string)attribute.MethodName, new Type[0]); if (method != null) { - var types = (IEnumerable)method.Invoke(null, new object[0]); - foreach (var knownType in types) + var types = method.Invoke(null, new object[0]) as IEnumerable; + if (types != null) { - if (knownType.Name == discriminatorValue) + foreach (var knownType in types) { - return knownType; + if (knownType.Name == discriminatorValue) + { + return knownType; + } } } return null; @@ -203,7 +208,7 @@ private static Type GetSubtypeFromKnownTypeAttributes(Type objectType, string di return null; } - private static Type GetObjectSubtype(Type baseType, string discriminatorValue) + private static Type? GetObjectSubtype(Type baseType, string discriminatorValue) { var jsonInheritanceAttributes = baseType .GetTypeInfo() @@ -213,7 +218,7 @@ private static Type GetObjectSubtype(Type baseType, string discriminatorValue) return jsonInheritanceAttributes.SingleOrDefault(a => a.Key == discriminatorValue)?.Type; } - private static string GetSubtypeDiscriminator(Type objectType) + private static string? GetSubtypeDiscriminator(Type objectType) { var jsonInheritanceAttributes = objectType .GetTypeInfo() diff --git a/src/NJsonSchema/DefaultTypeNameGenerator.cs b/src/NJsonSchema/DefaultTypeNameGenerator.cs index 6c025cec7..417270ead 100644 --- a/src/NJsonSchema/DefaultTypeNameGenerator.cs +++ b/src/NJsonSchema/DefaultTypeNameGenerator.cs @@ -35,11 +35,11 @@ public IEnumerable ReservedTypeNames public IDictionary TypeNameMappings => _typeNameMappings; /// - public virtual string Generate(JsonSchema schema, string typeNameHint, IEnumerable reservedTypeNames) + public virtual string Generate(JsonSchema schema, string? typeNameHint, IEnumerable reservedTypeNames) { if (string.IsNullOrEmpty(typeNameHint) && !string.IsNullOrEmpty(schema.DocumentPath)) { - typeNameHint = schema.DocumentPath.Replace("\\", "/").Split('/').Last(); + typeNameHint = schema.DocumentPath!.Replace("\\", "/").Split('/').Last(); } typeNameHint ??= ""; @@ -74,7 +74,7 @@ public virtual string Generate(JsonSchema schema, string typeNameHint, IEnumerab /// The schema. /// The type name hint. /// The type name. - protected virtual string Generate(JsonSchema schema, string typeNameHint) + protected virtual string Generate(JsonSchema schema, string? typeNameHint) { if (string.IsNullOrEmpty(typeNameHint) && schema.HasTypeNameTitle) { @@ -95,9 +95,11 @@ private string GenerateAnonymousTypeName(string typeNameHint, IEnumerable(); if (!string.IsNullOrEmpty(jsonSchemaAttribute?.Name)) { - return jsonSchemaAttribute.Name; + return jsonSchemaAttribute!.Name!; } var nType = type.ToCachedType(); diff --git a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs index dacb549ee..66a265b14 100644 --- a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs +++ b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs @@ -212,13 +212,13 @@ public virtual void Generate(TSchemaType schema, ContextualType con public TSchemaType GenerateWithReference( ContextualType contextualType, JsonSchemaResolver schemaResolver, - Action transformation = null) + Action? transformation = null) where TSchemaType : JsonSchema, new() { return GenerateWithReferenceAndNullability(contextualType, false, schemaResolver, transformation); } - /// Generetes a schema directly or referenced for the requested schema type; + /// Generates a schema directly or referenced for the requested schema type; /// also adds nullability if required by looking at the type's . /// The resulted schema type which may reference the actual schema. /// The type of the schema to generate. @@ -227,7 +227,7 @@ public TSchemaType GenerateWithReference( /// The requested schema object. public TSchemaType GenerateWithReferenceAndNullability( ContextualType contextualType, JsonSchemaResolver schemaResolver, - Action transformation = null) + Action? transformation = null) where TSchemaType : JsonSchema, new() { var typeDescription = Settings.ReflectionService.GetDescription(contextualType, Settings); @@ -243,7 +243,7 @@ public TSchemaType GenerateWithReferenceAndNullability( /// The requested schema object. public virtual TSchemaType GenerateWithReferenceAndNullability( ContextualType contextualType, bool isNullable, JsonSchemaResolver schemaResolver, - Action transformation = null) + Action? transformation = null) where TSchemaType : JsonSchema, new() { var typeDescription = Settings.ReflectionService.GetDescription(contextualType, Settings); @@ -306,7 +306,7 @@ public virtual TSchemaType GenerateWithReferenceAndNullability( // See https://github.com/RicoSuter/NJsonSchema/issues/531 var useDirectReference = Settings.AllowReferencesWithProperties || - !JsonConvert.DeserializeObject(JsonConvert.SerializeObject(referencingSchema)).Properties().Any(); // TODO: Improve performance + JsonConvert.DeserializeObject(JsonConvert.SerializeObject(referencingSchema))?.Properties()?.Any() == false; // TODO: Improve performance if (useDirectReference && referencingSchema._oneOf.Count == 0) { @@ -337,7 +337,7 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription { var contextualType = typeDescription.ContextualType; - dynamic displayAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DisplayAttribute"); + dynamic? displayAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DisplayAttribute"); if (displayAttribute != null) { // GetName returns null if the Name property on the attribute is not specified. @@ -348,7 +348,7 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription } } - dynamic defaultValueAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DefaultValueAttribute"); + dynamic? defaultValueAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DefaultValueAttribute"); if (defaultValueAttribute != null) { if (typeDescription.IsEnum && @@ -362,11 +362,16 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription } } - dynamic regexAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RegularExpressionAttribute"); + dynamic? regexAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RegularExpressionAttribute"); if (regexAttribute != null) { if (typeDescription.IsDictionary) { + if (schema.AdditionalPropertiesSchema == null) + { + schema.AdditionalPropertiesSchema = new JsonSchema(); + } + schema.AdditionalPropertiesSchema.Pattern = regexAttribute.Pattern; } else @@ -387,33 +392,33 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription } } - dynamic minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MinLengthAttribute"); - if (minLengthAttribute != null && minLengthAttribute.Length != null) + dynamic? minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MinLengthAttribute"); + if (minLengthAttribute?.Length != null) { if (typeDescription.Type == JsonObjectType.String) { - schema.MinLength = minLengthAttribute.Length; + schema.MinLength = minLengthAttribute?.Length; } else if (typeDescription.Type == JsonObjectType.Array) { - schema.MinItems = minLengthAttribute.Length; + schema.MinItems = minLengthAttribute?.Length; } } - dynamic maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MaxLengthAttribute"); - if (maxLengthAttribute != null && maxLengthAttribute.Length != null) + dynamic? maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.MaxLengthAttribute"); + if (maxLengthAttribute?.Length != null) { if (typeDescription.Type == JsonObjectType.String) { - schema.MaxLength = maxLengthAttribute.Length; + schema.MaxLength = maxLengthAttribute?.Length; } else if (typeDescription.Type == JsonObjectType.Array) { - schema.MaxItems = maxLengthAttribute.Length; + schema.MaxItems = maxLengthAttribute?.Length; } } - dynamic stringLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.StringLengthAttribute"); + dynamic? stringLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.StringLengthAttribute"); if (stringLengthAttribute != null) { if (typeDescription.Type == JsonObjectType.String) @@ -423,7 +428,7 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription } } - dynamic dataTypeAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DataTypeAttribute"); + dynamic? dataTypeAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DataTypeAttribute"); if (dataTypeAttribute != null) { var dataType = dataTypeAttribute.DataType.ToString(); @@ -438,14 +443,14 @@ public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription /// The value type. /// The default value. /// The converted default value. - public virtual object ConvertDefaultValue(ContextualType type, object defaultValue) + public virtual object? ConvertDefaultValue(ContextualType type, object? defaultValue) { if (defaultValue != null && defaultValue.GetType().GetTypeInfo().IsEnum) { var hasStringEnumConverter = Settings.ReflectionService.IsStringEnum(type, Settings); if (hasStringEnumConverter) { - return defaultValue.ToString(); + return defaultValue?.ToString(); } else { @@ -461,7 +466,7 @@ public virtual object ConvertDefaultValue(ContextualType type, object defaultVal /// Generates the example from the type's xml docs. /// The type. /// The JToken or null. - public virtual object GenerateExample(ContextualType type) + public virtual object? GenerateExample(ContextualType type) { if (Settings.GenerateExamples && Settings.UseXmlDocumentation) { @@ -481,7 +486,7 @@ public virtual object GenerateExample(ContextualType type) /// Generates the example from the accesor's xml docs. /// The accessor info. /// The JToken or null. - public virtual object GenerateExample(ContextualAccessorInfo accessorInfo) + public virtual object? GenerateExample(ContextualAccessorInfo accessorInfo) { if (Settings.GenerateExamples && Settings.UseXmlDocumentation) { @@ -498,7 +503,7 @@ public virtual object GenerateExample(ContextualAccessorInfo accessorInfo) return null; } - private object GenerateExample(string xmlDocs) + private object? GenerateExample(string xmlDocs) { try { @@ -542,7 +547,7 @@ protected virtual void GenerateObject(JsonSchema schema, JsonTypeDescription typ schema.Description = type.ToCachedType().GetDescription(Settings); schema.Example = GenerateExample(type.ToContextualType()); - dynamic obsoleteAttribute = type.GetTypeInfo().GetCustomAttributes(false).FirstAssignableToTypeNameOrDefault("System.ObsoleteAttribute"); + dynamic? obsoleteAttribute = type.GetTypeInfo().GetCustomAttributes(false).FirstAssignableToTypeNameOrDefault("System.ObsoleteAttribute"); if (obsoleteAttribute != null) { schema.IsDeprecated = true; @@ -566,7 +571,7 @@ protected virtual void GenerateObject(JsonSchema schema, JsonTypeDescription typ /// Gets the properties of the given type or null to take all properties. /// The type. /// The property names or null for all. - public virtual string[] GetTypeProperties(Type type) + public virtual string[]? GetTypeProperties(Type type) { if (type == typeof(Exception)) { @@ -590,7 +595,7 @@ protected virtual void GenerateArray( typeDescription.ApplyType(schema); var jsonSchemaAttribute = contextualType.GetInheritedAttribute(); - var itemType = jsonSchemaAttribute?.ArrayItem.ToContextualType() ?? + var itemType = jsonSchemaAttribute?.ArrayItem?.ToContextualType() ?? contextualType.EnumerableItemType ?? contextualType.GenericArguments.FirstOrDefault(); @@ -618,16 +623,16 @@ protected virtual void GenerateArray( schema.Item = JsonSchema.CreateAnySchema(); } - dynamic minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name); + dynamic? minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name); if (minLengthAttribute != null && ObjectExtensions.HasProperty(minLengthAttribute, "Length")) { - schema.MinItems = minLengthAttribute.Length; + schema.MinItems = minLengthAttribute?.Length; } - dynamic maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name); + dynamic? maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name); if (maxLengthAttribute != null && ObjectExtensions.HasProperty(maxLengthAttribute, "Length")) { - schema.MaxItems = maxLengthAttribute.Length; + schema.MaxItems = maxLengthAttribute?.Length; } } @@ -670,16 +675,16 @@ protected virtual void GenerateDictionary(TSchemaType schema, JsonT schema.AllowAdditionalProperties = true; } - dynamic minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name); + dynamic? minLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MinLengthAttribute", TypeNameStyle.Name); if (minLengthAttribute != null && ObjectExtensions.HasProperty(minLengthAttribute, "Length")) { - schema.MinProperties = minLengthAttribute.Length; + schema.MinProperties = minLengthAttribute?.Length; } - dynamic maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name); + dynamic? maxLengthAttribute = contextualType.ContextAttributes.FirstAssignableToTypeNameOrDefault("MaxLengthAttribute", TypeNameStyle.Name); if (maxLengthAttribute != null && ObjectExtensions.HasProperty(maxLengthAttribute, "Length")) { - schema.MaxProperties = maxLengthAttribute.Length; + schema.MaxProperties = maxLengthAttribute?.Length; } } @@ -706,11 +711,11 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD else { // EnumMember only checked if StringEnumConverter is used - var attributes = contextualType.Type.GetRuntimeField(enumName).GetCustomAttributes(); - dynamic enumMemberAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.Runtime.Serialization.EnumMemberAttribute"); - if (enumMemberAttribute != null && !string.IsNullOrEmpty(enumMemberAttribute.Value)) + var attributes = contextualType.Type.GetRuntimeField(enumName)?.GetCustomAttributes(); + dynamic? enumMemberAttribute = attributes?.FirstAssignableToTypeNameOrDefault("System.Runtime.Serialization.EnumMemberAttribute"); + if (!string.IsNullOrEmpty(enumMemberAttribute?.Value)) { - schema.Enumeration.Add((string)enumMemberAttribute.Value); + schema.Enumeration.Add((string)enumMemberAttribute!.Value); } else { @@ -862,7 +867,7 @@ private void GenerateEnum( public bool IsAbstractProperty(ContextualMemberInfo memberInfo) { return memberInfo is ContextualPropertyInfo propertyInfo && - !propertyInfo.PropertyInfo.DeclaringType.GetTypeInfo().IsInterface && + propertyInfo.PropertyInfo.DeclaringType?.GetTypeInfo().IsInterface == false && (propertyInfo.PropertyInfo.GetMethod?.IsAbstract == true || propertyInfo.PropertyInfo.SetMethod?.IsAbstract == true); } @@ -942,7 +947,7 @@ private void AddKnownType(Type type, JsonSchemaResolver schemaResolver) } } - private JsonSchema GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver) + private JsonSchema? GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver) { var baseType = type.BaseType; if (baseType != null && baseType.Type != typeof(object) && baseType.Type != typeof(ValueType)) @@ -1037,35 +1042,39 @@ private void GenerateInheritanceDiscriminator(Type type, JsonSchema schema, Json if (discriminatorConverter != null) { var discriminatorName = TryGetInheritanceDiscriminatorName(discriminatorConverter); - - // Existing property can be discriminator only if it has String type - if (typeSchema.Properties.TryGetValue(discriminatorName, out var existingProperty)) + if (discriminatorName is not null) { - if (!existingProperty.ActualTypeSchema.Type.IsInteger() && - !existingProperty.ActualTypeSchema.Type.IsString()) + // Existing property can be discriminator only if it has String type + if (typeSchema.Properties.TryGetValue(discriminatorName, out var existingProperty)) { - throw new InvalidOperationException("The JSON discriminator property '" + discriminatorName + "' must be a string|int property on type '" + type.FullName + "' (it is recommended to not implement the discriminator property at all)."); - } + if (!existingProperty.ActualTypeSchema.Type.IsInteger() && + !existingProperty.ActualTypeSchema.Type.IsString()) + { + throw new InvalidOperationException("The JSON discriminator property '" + discriminatorName + + "' must be a string|int property on type '" + type.FullName + + "' (it is recommended to not implement the discriminator property at all)."); + } - existingProperty.IsRequired = true; - } + existingProperty.IsRequired = true; + } - var discriminator = new OpenApiDiscriminator - { - JsonInheritanceConverter = discriminatorConverter, - PropertyName = discriminatorName - }; + var discriminator = new OpenApiDiscriminator + { + JsonInheritanceConverter = discriminatorConverter, + PropertyName = discriminatorName + }; - typeSchema.DiscriminatorObject = discriminator; + typeSchema.DiscriminatorObject = discriminator; - if (!typeSchema.Properties.ContainsKey(discriminatorName)) - { - typeSchema.Properties[discriminatorName] = new JsonSchemaProperty + if (!typeSchema.Properties.ContainsKey(discriminatorName)) { - Type = JsonObjectType.String, - IsRequired = true - }; - } + typeSchema.Properties[discriminatorName] = new JsonSchemaProperty + { + Type = JsonObjectType.String, + IsRequired = true + }; + } + } } else { @@ -1075,12 +1084,12 @@ private void GenerateInheritanceDiscriminator(Type type, JsonSchema schema, Json } } - private object TryGetInheritanceDiscriminatorConverter(Type type) + private object? TryGetInheritanceDiscriminatorConverter(Type type) { var typeAttributes = type.GetTypeInfo().GetCustomAttributes(false).OfType(); // support for NJsonSchema provided inheritance converters - dynamic jsonConverterAttribute = typeAttributes.FirstAssignableToTypeNameOrDefault(nameof(JsonConverterAttribute), TypeNameStyle.Name); + dynamic? jsonConverterAttribute = typeAttributes.FirstAssignableToTypeNameOrDefault(nameof(JsonConverterAttribute), TypeNameStyle.Name); if (jsonConverterAttribute != null) { var converterType = (Type)jsonConverterAttribute.ConverterType; @@ -1104,7 +1113,7 @@ private object TryGetInheritanceDiscriminatorConverter(Type type) if (jsonDerivedTypeAttributes.Any()) { - dynamic jsonPolymorphicAttribute = typeAttributes + dynamic? jsonPolymorphicAttribute = typeAttributes .FirstAssignableToTypeNameOrDefault("System.Text.Json.Serialization.JsonPolymorphicAttribute", TypeNameStyle.FullName); return new SystemTextJsonInheritanceWrapper(jsonPolymorphicAttribute?.TypeDiscriminatorPropertyName ?? "$type", jsonDerivedTypeAttributes); } @@ -1131,7 +1140,7 @@ public string GetDiscriminatorValue(Type type) } } - private string TryGetInheritanceDiscriminatorName(object jsonInheritanceConverter) + private string? TryGetInheritanceDiscriminatorName(object jsonInheritanceConverter) { return ObjectExtensions.TryGetPropertyValue( jsonInheritanceConverter, @@ -1155,7 +1164,7 @@ public void AddProperty( JsonSchema parentSchema, ContextualAccessorInfo property, JsonTypeDescription propertyTypeDescription, string propertyName, - Attribute requiredAttribute, bool hasRequiredAttribute, bool isNullable, object defaultValue, JsonSchemaResolver schemaResolver) + Attribute? requiredAttribute, bool hasRequiredAttribute, bool isNullable, object? defaultValue, JsonSchemaResolver schemaResolver) { // TODO: Extension method on JsonSchema class? @@ -1182,7 +1191,7 @@ public void AddProperty( } } - dynamic readOnlyAttribute = property.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.ReadOnlyAttribute"); + dynamic? readOnlyAttribute = property.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { propertySchema.IsReadOnly = readOnlyAttribute.IsReadOnly; @@ -1198,7 +1207,7 @@ public void AddProperty( propertySchema.Example = GenerateExample(property); } - dynamic obsoleteAttribute = property.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ObsoleteAttribute"); + dynamic? obsoleteAttribute = property.ContextAttributes.FirstAssignableToTypeNameOrDefault("System.ObsoleteAttribute"); if (obsoleteAttribute != null) { propertySchema.IsDeprecated = true; @@ -1265,7 +1274,7 @@ public bool IsPropertyIgnoredBySettings(ContextualAccessorInfo accessorInfo) /// /// /// - public dynamic GetDataMemberAttribute(ContextualAccessorInfo accessorInfo, Type parentType) + public dynamic? GetDataMemberAttribute(ContextualAccessorInfo accessorInfo, Type parentType) { if (!HasDataContractAttribute(parentType)) { @@ -1283,7 +1292,7 @@ private bool HasDataContractAttribute(Type parentType) private void ApplyRangeAttribute(JsonSchema schema, IEnumerable parentAttributes) { - dynamic rangeAttribute = parentAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RangeAttribute"); + dynamic? rangeAttribute = parentAttributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RangeAttribute"); if (rangeAttribute != null) { if (rangeAttribute.Minimum != null) @@ -1352,7 +1361,7 @@ private static void ApplyTypeExtensionDataAttributes(JsonSchema schema, IJsonSch { if (extensionAttributes.Any()) { - var extensionData = new Dictionary(); + var extensionData = new Dictionary(); foreach (var kvp in extensionAttributes .SelectMany(attribute => attribute.ExtensionData)) { diff --git a/src/NJsonSchema/Generation/JsonSchemaGeneratorSettings.cs b/src/NJsonSchema/Generation/JsonSchemaGeneratorSettings.cs index b40031fbf..9d2f1987d 100644 --- a/src/NJsonSchema/Generation/JsonSchemaGeneratorSettings.cs +++ b/src/NJsonSchema/Generation/JsonSchemaGeneratorSettings.cs @@ -22,8 +22,10 @@ namespace NJsonSchema.Generation public abstract class JsonSchemaGeneratorSettings : IXmlDocsSettings { /// Initializes a new instance of the class. - public JsonSchemaGeneratorSettings() + public JsonSchemaGeneratorSettings(IReflectionService reflectionService) { + ReflectionService = reflectionService; + DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.Null; DefaultDictionaryValueReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull; diff --git a/src/NJsonSchema/Generation/JsonTypeDescription.cs b/src/NJsonSchema/Generation/JsonTypeDescription.cs index 17282cfcf..c21369d33 100644 --- a/src/NJsonSchema/Generation/JsonTypeDescription.cs +++ b/src/NJsonSchema/Generation/JsonTypeDescription.cs @@ -29,7 +29,7 @@ private JsonTypeDescription(ContextualType type, JsonObjectType jsonType, bool i /// Specifies whether the type is nullable. /// The format string (may be null). /// The description. - public static JsonTypeDescription Create(ContextualType type, JsonObjectType jsonType, bool isNullable, string format) + public static JsonTypeDescription Create(ContextualType type, JsonObjectType jsonType, bool isNullable, string? format) { return new JsonTypeDescription(type, jsonType, isNullable) { @@ -76,7 +76,7 @@ public static JsonTypeDescription CreateForEnumeration(ContextualType type, Json public bool IsEnum { get; private set; } /// Gets the format string. - public string Format { get; private set; } + public string? Format { get; private set; } /// Gets or sets a value indicating whether the type is nullable. public bool IsNullable { get; set; } @@ -87,7 +87,7 @@ public static JsonTypeDescription CreateForEnumeration(ContextualType type, Json /// Gets a value indicating whether this is an any type (e.g. object). public bool IsAny => Type == JsonObjectType.None; - /// Specifices whether the type requires a reference. + /// Specifies whether the type requires a reference. /// The type mappers. /// true or false. public bool RequiresSchemaReference(IEnumerable typeMappers) diff --git a/src/NJsonSchema/Generation/ReflectionServiceBase.cs b/src/NJsonSchema/Generation/ReflectionServiceBase.cs index 3421ad86a..8f30b6709 100644 --- a/src/NJsonSchema/Generation/ReflectionServiceBase.cs +++ b/src/NJsonSchema/Generation/ReflectionServiceBase.cs @@ -339,10 +339,10 @@ protected virtual bool IsDictionaryType(ContextualType contextualType) private bool HasStringEnumConverter(ContextualType contextualType) { - dynamic jsonConverterAttribute = contextualType.Attributes?.FirstOrDefault(a => a.GetType().Name == "JsonConverterAttribute"); + dynamic? jsonConverterAttribute = contextualType.Attributes?.FirstOrDefault(a => a.GetType().Name == "JsonConverterAttribute"); if (jsonConverterAttribute != null && ObjectExtensions.HasProperty(jsonConverterAttribute, "ConverterType")) { - var converterType = (Type)jsonConverterAttribute.ConverterType; + var converterType = jsonConverterAttribute?.ConverterType as Type; if (converterType != null) { return converterType.IsAssignableToTypeName("StringEnumConverter", TypeNameStyle.Name) || diff --git a/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs b/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs index 381f23882..48a2ec6cb 100644 --- a/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs +++ b/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs @@ -10,6 +10,7 @@ using NJsonSchema; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; namespace NJsonSchema.Generation @@ -55,7 +56,7 @@ private JToken Generate(JsonSchema schema, Stack schemaStack) schemaStack.Push(schema); if (schemaStack.Count(s => s == schema) > _settings.MaxRecursionLevel) { - return null; + return new JValue((object?)null); } if (schema.Type.IsObject() || GetPropertiesToGenerate(schema.AllOf).Any()) @@ -104,7 +105,7 @@ private JToken Generate(JsonSchema schema, Stack schemaStack) { if (schema.IsEnumeration) { - return JToken.FromObject(schema.Enumeration.First()); + return JToken.FromObject(schema.Enumeration.First()!); } else if (schema.Type.IsInteger()) { @@ -124,26 +125,27 @@ private JToken Generate(JsonSchema schema, Stack schemaStack) } } - return null; + return new JValue((object?)null); } finally { schemaStack.Pop(); } } + private JToken HandleNumberType(JsonSchema schema) { - if (schema.ExclusiveMinimumRaw != null) + if (schema.ExclusiveMinimumRaw?.Equals(true) == true && schema.Minimum != null) { - return JToken.FromObject((decimal)(float.Parse(schema.Minimum.ToString()) + 0.1)); + return JToken.FromObject(decimal.Parse(schema.Minimum.Value.ToString(CultureInfo.InvariantCulture)) + 0.1m); } else if (schema.ExclusiveMinimum != null) { - return JToken.FromObject(decimal.Parse(schema.ExclusiveMinimum.ToString())); + return JToken.FromObject(decimal.Parse(schema.ExclusiveMinimum.Value.ToString(CultureInfo.InvariantCulture))); } else if (schema.Minimum.HasValue) { - return decimal.Parse(schema.Minimum.ToString()); + return decimal.Parse(schema.Minimum.ToString()!); } return JToken.FromObject(0.0); } @@ -165,7 +167,7 @@ private JToken HandleIntegerType(JsonSchema schema) return JToken.FromObject(0); } - private JToken HandleStringType(JsonSchema schema, JsonSchemaProperty property) + private JToken HandleStringType(JsonSchema schema, JsonSchemaProperty? property) { if (schema.Format == JsonFormatStrings.Date) { diff --git a/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs b/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs index 3db02f340..7a95e6616 100644 --- a/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs +++ b/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs @@ -127,7 +127,7 @@ public override string ConvertEnumValue(object value, SystemTextJsonSchemaGenera } var json = JsonSerializer.Serialize(value, value.GetType(), serializerOptions); - return JsonSerializer.Deserialize(json); + return JsonSerializer.Deserialize(json)!; } /// @@ -138,12 +138,12 @@ public override string GetPropertyName(ContextualAccessorInfo accessorInfo, Json private string GetPropertyName(ContextualAccessorInfo accessorInfo, SystemTextJsonSchemaGeneratorSettings settings) { - dynamic jsonPropertyNameAttribute = accessorInfo.ContextAttributes + dynamic? jsonPropertyNameAttribute = accessorInfo.ContextAttributes .FirstAssignableToTypeNameOrDefault("System.Text.Json.Serialization.JsonPropertyNameAttribute", TypeNameStyle.FullName); - if (jsonPropertyNameAttribute != null && !string.IsNullOrEmpty(jsonPropertyNameAttribute.Name)) + if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name)) { - return jsonPropertyNameAttribute.Name; + return jsonPropertyNameAttribute!.Name; } if (settings.SerializerOptions.PropertyNamingPolicy != null) diff --git a/src/NJsonSchema/Generation/SystemTextJsonSchemaGeneratorSettings.cs b/src/NJsonSchema/Generation/SystemTextJsonSchemaGeneratorSettings.cs index b78e93448..517dd8052 100644 --- a/src/NJsonSchema/Generation/SystemTextJsonSchemaGeneratorSettings.cs +++ b/src/NJsonSchema/Generation/SystemTextJsonSchemaGeneratorSettings.cs @@ -19,9 +19,8 @@ public class SystemTextJsonSchemaGeneratorSettings : JsonSchemaGeneratorSettings /// /// /// - public SystemTextJsonSchemaGeneratorSettings() + public SystemTextJsonSchemaGeneratorSettings() : base(new SystemTextJsonReflectionService()) { - ReflectionService = new SystemTextJsonReflectionService(); } /// Gets or sets the System.Text.Json serializer options. diff --git a/src/NJsonSchema/IDocumentPathProvider.cs b/src/NJsonSchema/IDocumentPathProvider.cs index 77fecfd4c..ae29c5be0 100644 --- a/src/NJsonSchema/IDocumentPathProvider.cs +++ b/src/NJsonSchema/IDocumentPathProvider.cs @@ -15,6 +15,6 @@ public interface IDocumentPathProvider { /// Gets the document path (URI or file path). [JsonIgnore] - string DocumentPath { get; set; } + string? DocumentPath { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema/IJsonExtensionObject.cs b/src/NJsonSchema/IJsonExtensionObject.cs index a7ca5f989..4ce78a365 100644 --- a/src/NJsonSchema/IJsonExtensionObject.cs +++ b/src/NJsonSchema/IJsonExtensionObject.cs @@ -14,6 +14,6 @@ namespace NJsonSchema public interface IJsonExtensionObject { /// Gets or sets the extension data (i.e. additional properties which are not directly defined by the JSON object). - IDictionary ExtensionData { get; set; } + IDictionary? ExtensionData { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema/ITypeNameGenerator.cs b/src/NJsonSchema/ITypeNameGenerator.cs index 54f2b3170..c26046f45 100644 --- a/src/NJsonSchema/ITypeNameGenerator.cs +++ b/src/NJsonSchema/ITypeNameGenerator.cs @@ -18,6 +18,6 @@ public interface ITypeNameGenerator /// The type name hint (the property name or definition key). /// The reserved type names. /// The new name. - string Generate(JsonSchema schema, string typeNameHint, IEnumerable reservedTypeNames); + string Generate(JsonSchema schema, string? typeNameHint, IEnumerable reservedTypeNames); } } \ No newline at end of file diff --git a/src/NJsonSchema/Infrastructure/CollectionProxy.cs b/src/NJsonSchema/Infrastructure/CollectionProxy.cs deleted file mode 100644 index 4e4f5cc32..000000000 --- a/src/NJsonSchema/Infrastructure/CollectionProxy.cs +++ /dev/null @@ -1,57 +0,0 @@ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace NJsonSchema.Infrastructure -{ - public class CollectionProxy : ICollection - where TImplementation : TInterface - { - private readonly ICollection _collection; - - public CollectionProxy(ICollection collection) - { - _collection = collection; - } - - public IEnumerator GetEnumerator() - { - return _collection.OfType().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void Add(TInterface item) - { - _collection.Add((TImplementation)item); - } - - public void Clear() - { - _collection.Clear(); - } - - public bool Contains(TInterface item) - { - return _collection.Contains((TImplementation)item); - } - - public void CopyTo(TInterface[] array, int arrayIndex) - { - _collection.CopyTo(array.OfType().ToArray(), arrayIndex); - } - - public bool Remove(TInterface item) - { - return _collection.Remove((TImplementation)item); - } - - public int Count => _collection.Count; - - public bool IsReadOnly => _collection.IsReadOnly; - } -} \ No newline at end of file diff --git a/src/NJsonSchema/Infrastructure/DictionaryProxy.cs b/src/NJsonSchema/Infrastructure/DictionaryProxy.cs deleted file mode 100644 index 8245449f1..000000000 --- a/src/NJsonSchema/Infrastructure/DictionaryProxy.cs +++ /dev/null @@ -1,94 +0,0 @@ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace NJsonSchema.Infrastructure -{ - internal sealed class DictionaryProxy : IDictionary - where TImplementation : TInterface - { - private readonly IDictionary _dictionary; - - public DictionaryProxy(IDictionary dictionary) - { - _dictionary = dictionary; - } - - public IEnumerator> GetEnumerator() - { - return _dictionary.Select(t => new KeyValuePair(t.Key, t.Value)).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void Add(KeyValuePair item) - { - _dictionary.Add(item.Key, (TImplementation)item.Value); - } - - public void Clear() - { - _dictionary.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return _dictionary.Contains(new KeyValuePair(item.Key, (TImplementation)item.Value)); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - _dictionary.CopyTo(array.Select(t => new KeyValuePair(t.Key, (TImplementation)t.Value)).ToArray(), arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return _dictionary.Remove(new KeyValuePair(item.Key, (TImplementation)item.Value)); - } - - public int Count => _dictionary.Count; - - public bool IsReadOnly => _dictionary.IsReadOnly; - - public void Add(TKey key, TInterface value) - { - _dictionary.Add(key, (TImplementation)value); - } - - public bool ContainsKey(TKey key) - { - return _dictionary.ContainsKey(key); - } - - public bool Remove(TKey key) - { - return _dictionary.Remove(key); - } - - public bool TryGetValue(TKey key, out TInterface value) - { - if (_dictionary.TryGetValue(key, out var x)) - { - value = x; - return true; - } - - value = default(TInterface); - return false; - } - - public TInterface this[TKey key] - { - get => _dictionary[key]; - set => _dictionary[key] = (TImplementation)value; - } - - public ICollection Keys => _dictionary.Keys; - - public ICollection Values => _dictionary.Values.OfType().ToList(); - } -} \ No newline at end of file diff --git a/src/NJsonSchema/Infrastructure/DynamicApis.cs b/src/NJsonSchema/Infrastructure/DynamicApis.cs index 10da52f75..c14933be9 100644 --- a/src/NJsonSchema/Infrastructure/DynamicApis.cs +++ b/src/NJsonSchema/Infrastructure/DynamicApis.cs @@ -6,66 +6,38 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- -using Namotion.Reflection; using System; +using System.IO; using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; namespace NJsonSchema.Infrastructure { /// Provides dynamic access to framework APIs. public static class DynamicApis { - private static readonly Type XPathExtensionsType; - private static readonly Type FileType; - private static readonly Type DirectoryType; - private static readonly Type PathType; - private static readonly Type DecompressionMethodsType; - private static readonly Type HttpClientHandlerType; - private static readonly Type HttpClientType; + private static readonly Type? HttpClientType; + private static readonly Type? HttpClientHandlerType; + private static readonly Type? DecompressionMethodsType; static DynamicApis() { - XPathExtensionsType = TryLoadType( - "System.Xml.XPath.Extensions, System.Xml.XPath.XDocument", - "System.Xml.XPath.Extensions, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); - - DecompressionMethodsType = TryLoadType( - "System.Net.DecompressionMethods, System.Net.Primitives", - "System.Net.DecompressionMethods, System.Net.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + HttpClientType = TryLoadType( + "System.Net.Http.HttpClient, System.Net.Http", + "System.Net.Http.HttpClient, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); HttpClientHandlerType = TryLoadType( "System.Net.Http.HttpClientHandler, System.Net.Http", "System.Net.Http.HttpClientHandler, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - HttpClientType = TryLoadType( - "System.Net.Http.HttpClient, System.Net.Http", - "System.Net.Http.HttpClient, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - - FileType = TryLoadType("System.IO.File, System.IO.FileSystem", "System.IO.File"); - DirectoryType = TryLoadType("System.IO.Directory, System.IO.FileSystem", "System.IO.Directory"); - PathType = TryLoadType("System.IO.Path, System.IO.FileSystem", "System.IO.Path"); + DecompressionMethodsType = TryLoadType( + "System.Net.DecompressionMethods, System.Net.Primitives", + "System.Net.DecompressionMethods, System.Net.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); } - /// Gets a value indicating whether file APIs are available. - public static bool SupportsFileApis => FileType != null; - - /// Gets a value indicating whether path APIs are available. - public static bool SupportsPathApis => PathType != null; - - /// Gets a value indicating whether path APIs are available. - public static bool SupportsDirectoryApis => DirectoryType != null; - - /// Gets a value indicating whether XPath APIs are available. - public static bool SupportsXPathApis => XPathExtensionsType != null; - /// Gets a value indicating whether WebClient APIs are available. - public static bool SupportsHttpClientApis => HttpClientType != null; + public static bool SupportsHttpClientApis => HttpClientType != null && HttpClientHandlerType != null && DecompressionMethodsType != null; /// Request the given URL via HTTP. /// The URL. @@ -79,14 +51,14 @@ public static async Task HttpGetAsync(string url, CancellationToken canc throw new NotSupportedException("The System.Net.Http.HttpClient API is not available on this platform."); } - using (dynamic handler = (IDisposable)Activator.CreateInstance(HttpClientHandlerType)) - using (dynamic client = (IDisposable)Activator.CreateInstance(HttpClientType, new[] { handler })) + using (dynamic handler = (IDisposable)Activator.CreateInstance(HttpClientHandlerType!)!) + using (dynamic client = (IDisposable)Activator.CreateInstance(HttpClientType!, new[] { handler })!) { handler.UseDefaultCredentials = true; // enable all decompression methods var calculatedAllValue = GenerateAllDecompressionMethodsEnumValue(); - var allDecompressionMethodsValue = Enum.ToObject(DecompressionMethodsType, calculatedAllValue); + var allDecompressionMethodsValue = Enum.ToObject(DecompressionMethodsType!, calculatedAllValue); handler.AutomaticDecompression = (dynamic)allDecompressionMethodsValue; var response = await client.GetAsync(url, cancellationToken).ConfigureAwait(false); @@ -104,7 +76,7 @@ private static int GenerateAllDecompressionMethodsEnumValue() // additional ones in the future) if the loaded httpclient supports it. // while the existing values would allow doing a Sum, we still bitwise or to be defensive about // potential additions in the future of values like "GZipOrDeflate" - var calculatedAllValue = Enum.GetValues(DecompressionMethodsType) + var calculatedAllValue = Enum.GetValues(DecompressionMethodsType!) .Cast() .Where(val => val > 0) // filter to only positive so we're not including All or None .Aggregate(0, (accumulated, newValue) => accumulated | newValue); @@ -112,219 +84,6 @@ private static int GenerateAllDecompressionMethodsEnumValue() return calculatedAllValue; } - /// Gets the current working directory. - /// The directory path. - /// The System.IO.Directory API is not available on this platform. - public static string DirectoryGetCurrentDirectory() - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - return (string)DirectoryType.GetRuntimeMethod("GetCurrentDirectory", new Type[] { }).Invoke(null, new object[] { }); - } - - /// Gets the current working directory. - /// The directory path. - /// The System.IO.Directory API is not available on this platform. - public static string[] DirectoryGetDirectories(string directory) - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - return (string[])DirectoryType.GetRuntimeMethod("GetDirectories", new[] { typeof(string) }).Invoke(null, new object[] { directory }); - } - - /// Gets the files of the given directory. - /// The directory. - /// The filter. - /// The file paths. - /// The System.IO.Directory API is not available on this platform. - public static string[] DirectoryGetFiles(string directory, string filter) - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - return (string[])DirectoryType.GetRuntimeMethod("GetFiles", - new[] { typeof(string), typeof(string) }).Invoke(null, new object[] { directory, filter }); - } - - /// Retrieves the parent directory of the specified path, including both absolute and relative paths.. - /// The directory path. - /// The System.IO.Directory API is not available on this platform. - public static string DirectoryGetParent(string path) - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - return DirectoryType.GetRuntimeMethod("GetParent", new[] { typeof(string) }).Invoke(null, new object[] { path }).TryGetPropertyValue("FullName"); - } - - /// Creates a directory. - /// The directory. - /// The System.IO.Directory API is not available on this platform. - public static void DirectoryCreateDirectory(string directory) - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - DirectoryType.GetRuntimeMethod("CreateDirectory", - new[] { typeof(string) }).Invoke(null, new object[] { directory }); - } - - /// Checks whether a directory exists. - /// The file path. - /// true or false - /// The System.IO.Directory API is not available on this platform. - public static bool DirectoryExists(string filePath) - { - if (!SupportsDirectoryApis) - { - throw new NotSupportedException("The System.IO.Directory API is not available on this platform."); - } - - if (string.IsNullOrEmpty(filePath)) - { - return false; - } - - return (bool)DirectoryType.GetRuntimeMethod("Exists", - new[] { typeof(string) }).Invoke(null, new object[] { filePath }); - } - - /// Checks whether a file exists. - /// The file path. - /// true or false - /// The System.IO.File API is not available on this platform. - public static bool FileExists(string filePath) - { - if (!SupportsFileApis) - { - throw new NotSupportedException("The System.IO.File API is not available on this platform."); - } - - if (string.IsNullOrEmpty(filePath)) - { - return false; - } - - return (bool)FileType.GetRuntimeMethod("Exists", - new[] { typeof(string) }).Invoke(null, new object[] { filePath }); - } - - /// Reads all content of a file (UTF8 with or without BOM). - /// The file path. - /// The file content. - /// The System.IO.File API is not available on this platform. - public static string FileReadAllText(string filePath) - { - if (!SupportsFileApis) - { - throw new NotSupportedException("The System.IO.File API is not available on this platform."); - } - - return (string)FileType.GetRuntimeMethod("ReadAllText", - new[] { typeof(string), typeof(Encoding) }).Invoke(null, new object[] { filePath, Encoding.UTF8 }); - } - - /// Writes text to a file (UTF8 without BOM). - /// The file path. - /// The text. - /// - /// The System.IO.File API is not available on this platform. - public static void FileWriteAllText(string filePath, string text) - { - if (!SupportsFileApis) - { - throw new NotSupportedException("The System.IO.File API is not available on this platform."); - } - - // Default of encoding is StreamWriter.UTF8NoBOM - FileType.GetRuntimeMethod("WriteAllText", - new[] { typeof(string), typeof(string) }).Invoke(null, new object[] { filePath, text }); - } - - /// Combines two paths. - /// The path1. - /// The path2. - /// The combined path. - /// The System.IO.Path API is not available on this platform. - public static string PathCombine(string path1, string path2) - { - if (!SupportsPathApis) - { - throw new NotSupportedException("The System.IO.Path API is not available on this platform."); - } - - return (string)PathType.GetRuntimeMethod("Combine", new[] { typeof(string), typeof(string) }).Invoke(null, new object[] { path1, path2 }); - } - - /// Gets the file name from a given path. - /// The file path. - /// The directory name. - /// The System.IO.Path API is not available on this platform. - public static string PathGetFileName(string filePath) - { - if (!SupportsPathApis) - { - throw new NotSupportedException("The System.IO.Path API is not available on this platform."); - } - - return (string)PathType.GetRuntimeMethod("GetFileName", new[] { typeof(string) }).Invoke(null, new object[] { filePath }); - } - - /// Gets the full path from a given path - /// The path - /// The full path - /// The System.IO.Path API is not available on this platform. - public static string GetFullPath(string path) - { - if (!SupportsPathApis) - { - throw new NotSupportedException("The System.IO.Path API is not available on this platform."); - } - - return (string)PathType.GetRuntimeMethod("GetFullPath", new[] { typeof(string) }).Invoke(null, new object[] { path }); - } - - /// Gets the directory path of a file path. - /// The file path. - /// The directory name. - /// The System.IO.Path API is not available on this platform. - public static string PathGetDirectoryName(string filePath) - { - if (!SupportsPathApis) - { - throw new NotSupportedException("The System.IO.Path API is not available on this platform."); - } - - return (string)PathType.GetRuntimeMethod("GetDirectoryName", new[] { typeof(string) }).Invoke(null, new object[] { filePath }); - } - - /// Evaluates the XPath for a given XML document. - /// The document. - /// The path. - /// The value. - /// The System.Xml.XPath.Extensions API is not available on this platform. - public static object XPathEvaluate(XDocument document, string path) - { - if (!SupportsXPathApis) - { - throw new NotSupportedException("The System.Xml.XPath.Extensions API is not available on this platform."); - } - - return XPathExtensionsType.GetRuntimeMethod("XPathEvaluate", new[] { typeof(XDocument), typeof(string) }).Invoke(null, new object[] { document, path }); - } - /// /// Handle cases of specs in subdirectories having external references to specs also in subdirectories /// @@ -335,40 +94,41 @@ public static string HandleSubdirectoryRelativeReferences(string fullPath, strin { try { - if (!DynamicApis.DirectoryExists(DynamicApis.PathGetDirectoryName(fullPath))) + if (!Directory.Exists(Path.GetDirectoryName(fullPath))) { - string fileName = DynamicApis.PathGetFileName(fullPath); - string directoryName = DynamicApis.PathGetDirectoryName(fullPath); - string folderName = directoryName.Replace("\\", "/").Split('/').Last(); - if (!string.IsNullOrWhiteSpace(DynamicApis.DirectoryGetParent(directoryName))) + var fileName = Path.GetFileName(fullPath); + var directoryName = Path.GetDirectoryName(fullPath)!; + var folderName = directoryName.Replace("\\", "/").Split('/').Last(); + var parentDirectory = Directory.GetParent(directoryName); + if (!string.IsNullOrWhiteSpace(parentDirectory?.FullName)) { - foreach (string subDir in DynamicApis.DirectoryGetDirectories(DynamicApis.DirectoryGetParent(directoryName))) + foreach (string subDir in Directory.GetDirectories(parentDirectory!.FullName)) { - string expectedDir = DynamicApis.PathCombine(subDir, folderName); - string expectedFile = DynamicApis.PathCombine(expectedDir, fileName); - if (DynamicApis.DirectoryExists(expectedDir)) + var expectedDir = Path.Combine(subDir, folderName); + var expectedFile = Path.Combine(expectedDir, fileName); + if (Directory.Exists(expectedDir)) { - fullPath = DynamicApis.PathCombine(expectedDir, fileName); + fullPath = Path.Combine(expectedDir, fileName); break; } } } } - if (!DynamicApis.FileExists(fullPath)) + if (!File.Exists(fullPath)) { - string fileDir = DynamicApis.PathGetDirectoryName(fullPath); - if (DynamicApis.DirectoryExists(fileDir)) + var fileDir = Path.GetDirectoryName(fullPath); + if (Directory.Exists(fileDir)) { - string fileName = DynamicApis.PathGetFileName(fullPath); - string[] pathPieces = fullPath.Replace("\\", "/").Split('/'); - string subDirPiece = pathPieces[pathPieces.Length - 2]; - foreach (string subDir in DynamicApis.DirectoryGetDirectories(fileDir)) + var fileName = Path.GetFileName(fullPath); + var pathPieces = fullPath.Replace("\\", "/").Split('/'); + var subDirPiece = pathPieces[pathPieces.Length - 2]; + foreach (var subDir in Directory.GetDirectories(fileDir)) { - string expectedFile = DynamicApis.PathCombine(subDir, fileName); - if (DynamicApis.FileExists(expectedFile) && DynamicApis.FileReadAllText(expectedFile).Contains(jsonPath.Split('/').Last())) + var expectedFile = Path.Combine(subDir, fileName); + if (File.Exists(expectedFile) && File.ReadAllText(expectedFile).Contains(jsonPath.Split('/').Last())) { - fullPath = DynamicApis.PathCombine(subDir, fileName); + fullPath = Path.Combine(subDir, fileName); break; } } @@ -383,13 +143,7 @@ public static string HandleSubdirectoryRelativeReferences(string fullPath, strin } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Task FromResult(T result) - { - return Task.FromResult(result); - } - - private static Type TryLoadType(params string[] typeNames) + private static Type? TryLoadType(params string[] typeNames) { foreach (var typeName in typeNames) { diff --git a/src/NJsonSchema/Infrastructure/IgnoreEmptyCollectionsContractResolver.cs b/src/NJsonSchema/Infrastructure/IgnoreEmptyCollectionsContractResolver.cs index ffadce9e1..354bb35de 100644 --- a/src/NJsonSchema/Infrastructure/IgnoreEmptyCollectionsContractResolver.cs +++ b/src/NJsonSchema/Infrastructure/IgnoreEmptyCollectionsContractResolver.cs @@ -22,11 +22,11 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ if ((property.Required == Required.Default || property.Required == Required.DisallowNull) && property.PropertyType != typeof(string) && - typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo())) + typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(property.PropertyType?.GetTypeInfo())) { property.ShouldSerialize = instance => { - var enumerable = instance != null ? property.ValueProvider.GetValue(instance) as IEnumerable : null; + var enumerable = instance != null ? property.ValueProvider?.GetValue(instance) as IEnumerable : null; if (enumerable != null) { return enumerable.GetEnumerator().MoveNext(); diff --git a/src/NJsonSchema/Infrastructure/JsonSchemaSerialization.cs b/src/NJsonSchema/Infrastructure/JsonSchemaSerialization.cs index b3670e0a5..7423ad69b 100644 --- a/src/NJsonSchema/Infrastructure/JsonSchemaSerialization.cs +++ b/src/NJsonSchema/Infrastructure/JsonSchemaSerialization.cs @@ -27,7 +27,7 @@ public class JsonSchemaSerialization private static bool _isWriting; [ThreadStatic] - private static JsonSerializerSettings _currentSerializerSettings; + private static JsonSerializerSettings? _currentSerializerSettings; /// Gets or sets the current schema type. public static SchemaType CurrentSchemaType @@ -37,7 +37,7 @@ public static SchemaType CurrentSchemaType } /// Gets the current serializer settings. - public static JsonSerializerSettings CurrentSerializerSettings + public static JsonSerializerSettings? CurrentSerializerSettings { get => _currentSerializerSettings; private set => _currentSerializerSettings = value; @@ -85,8 +85,9 @@ public static string ToJson(object obj, SchemaType schemaType, IContractResolver /// The contract resolver. /// The deserialized schema. [Obsolete("Use FromJsonAsync with cancellation token instead.")] - public static Task FromJsonAsync(string json, SchemaType schemaType, string documentPath, + public static Task FromJsonAsync(string json, SchemaType schemaType, string? documentPath, Func referenceResolverFactory, IContractResolver contractResolver) + where T : notnull { return FromJsonAsync(json, schemaType, documentPath, referenceResolverFactory, contractResolver, CancellationToken.None); } @@ -99,8 +100,9 @@ public static Task FromJsonAsync(string json, SchemaType schemaType, strin /// The contract resolver. /// The cancellation token /// The deserialized schema. - public static Task FromJsonAsync(string json, SchemaType schemaType, string documentPath, - Func referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken = default) + public static Task FromJsonAsync(string json, SchemaType schemaType, string? documentPath, + Func referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken = default) + where T : notnull { var loader = () => FromJson(json, contractResolver); return FromJsonWithLoaderAsync(loader, schemaType, documentPath, referenceResolverFactory, contractResolver, cancellationToken); @@ -114,8 +116,9 @@ public static Task FromJsonAsync(string json, SchemaType schemaType, strin /// The contract resolver. /// The cancellation token /// The deserialized schema. - public static Task FromJsonAsync(Stream stream, SchemaType schemaType, string documentPath, - Func referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken = default) + public static Task FromJsonAsync(Stream stream, SchemaType schemaType, string? documentPath, + Func referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken = default) + where T : notnull { var loader = () => FromJson(stream, contractResolver); return FromJsonWithLoaderAsync(loader, schemaType, documentPath, referenceResolverFactory, contractResolver, cancellationToken); @@ -124,10 +127,11 @@ public static Task FromJsonAsync(Stream stream, SchemaType schemaType, str private static async Task FromJsonWithLoaderAsync( Func loader, SchemaType schemaType, - string documentPath, + string? documentPath, Func referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken) + where T : notnull { cancellationToken.ThrowIfCancellationRequested(); CurrentSchemaType = schemaType; @@ -146,7 +150,7 @@ private static async Task FromJsonWithLoaderAsync( { if (!string.IsNullOrEmpty(documentPath)) { - referenceResolver.AddDocumentReference(documentPath, referenceSchema); + referenceResolver.AddDocumentReference(documentPath!, referenceSchema); } } @@ -164,7 +168,7 @@ private static async Task FromJsonWithLoaderAsync( /// The JSON data. /// The contract resolver. /// The deserialized schema. - public static T FromJson(string json, IContractResolver contractResolver) + public static T? FromJson(string json, IContractResolver contractResolver) { IsWriting = true; UpdateCurrentSerializerSettings(contractResolver); @@ -183,7 +187,7 @@ public static T FromJson(string json, IContractResolver contractResolver) /// The JSON data stream. /// The contract resolver. /// The deserialized schema. - public static T FromJson(Stream stream, IContractResolver contractResolver) + public static T? FromJson(Stream stream, IContractResolver contractResolver) { IsWriting = true; UpdateCurrentSerializerSettings(contractResolver); @@ -194,7 +198,6 @@ public static T FromJson(Stream stream, IContractResolver contractResolver) using var jsonReader = new JsonTextReader(reader); var serializer = JsonSerializer.Create(CurrentSerializerSettings); - return serializer.Deserialize(jsonReader); } finally diff --git a/src/NJsonSchema/Infrastructure/PropertyRenameAndIgnoreSerializerContractResolver.cs b/src/NJsonSchema/Infrastructure/PropertyRenameAndIgnoreSerializerContractResolver.cs index e7061288e..b6892dea8 100644 --- a/src/NJsonSchema/Infrastructure/PropertyRenameAndIgnoreSerializerContractResolver.cs +++ b/src/NJsonSchema/Infrastructure/PropertyRenameAndIgnoreSerializerContractResolver.cs @@ -32,14 +32,14 @@ public PropertyRenameAndIgnoreSerializerContractResolver() /// One or more JSON properties to ignore. public void IgnoreProperty(Type type, params string[] jsonPropertyNames) { - if (!_ignores.ContainsKey(type.FullName)) + if (!_ignores.ContainsKey(type.FullName!)) { - _ignores[type.FullName] = new HashSet(); + _ignores[type.FullName!] = new HashSet(); } foreach (var prop in jsonPropertyNames) { - _ignores[type.FullName].Add(prop); + _ignores[type.FullName!].Add(prop); } } @@ -49,12 +49,12 @@ public void IgnoreProperty(Type type, params string[] jsonPropertyNames) /// The new JSON property name. public void RenameProperty(Type type, string propertyName, string newJsonPropertyName) { - if (!_renames.ContainsKey(type.FullName)) + if (!_renames.ContainsKey(type.FullName!)) { - _renames[type.FullName] = new Dictionary(); + _renames[type.FullName!] = new Dictionary(); } - _renames[type.FullName][propertyName] = newJsonPropertyName; + _renames[type.FullName!][propertyName] = newJsonPropertyName; } /// Creates a JsonProperty for the given System.Reflection.MemberInfo. @@ -65,7 +65,9 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ { var property = base.CreateProperty(member, memberSerialization); - if (IsIgnored(property.DeclaringType, property.PropertyName)) + if (property.DeclaringType != null && + property.PropertyName != null && + IsIgnored(property.DeclaringType, property.PropertyName)) { property.Ignored = true; @@ -73,7 +75,9 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ property.ShouldDeserialize = i => false; } - if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName)) + if (property.DeclaringType != null && + property.PropertyName != null && + IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName)) { property.PropertyName = newJsonPropertyName; } @@ -83,17 +87,17 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ private bool IsIgnored(Type type, string jsonPropertyName) { - if (!_ignores.ContainsKey(type.FullName)) + if (!_ignores.ContainsKey(type.FullName!)) { return false; } - return _ignores[type.FullName].Contains(jsonPropertyName); + return _ignores[type.FullName!].Contains(jsonPropertyName); } - private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName) + private bool IsRenamed(Type type, string jsonPropertyName, out string? newJsonPropertyName) { - if (!_renames.TryGetValue(type.FullName, out var renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName)) + if (!_renames.TryGetValue(type.FullName!, out var renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName)) { newJsonPropertyName = null; return false; diff --git a/src/NJsonSchema/Infrastructure/TypeExtensions.cs b/src/NJsonSchema/Infrastructure/TypeExtensions.cs index c06152fec..d6e33c8f5 100644 --- a/src/NJsonSchema/Infrastructure/TypeExtensions.cs +++ b/src/NJsonSchema/Infrastructure/TypeExtensions.cs @@ -62,13 +62,18 @@ private static string GetNameWithoutCache(ContextualAccessorInfo accessorInfo) var jsonPropertyAttribute = accessorInfo.AccessorType.GetContextAttribute(); if (jsonPropertyAttribute != null && !string.IsNullOrEmpty(jsonPropertyAttribute.PropertyName)) { - return jsonPropertyAttribute.PropertyName; + return jsonPropertyAttribute.PropertyName!; } var dataMemberAttribute = accessorInfo.AccessorType.GetContextAttribute(); if (dataMemberAttribute != null && !string.IsNullOrEmpty(dataMemberAttribute.Name)) { - var dataContractAttribute = accessorInfo.MemberInfo.DeclaringType.ToCachedType().GetInheritedAttribute(); + var dataContractAttribute = accessorInfo + .MemberInfo + .DeclaringType? + .ToCachedType() + .GetInheritedAttribute(); + if (dataContractAttribute != null) { return dataMemberAttribute.Name; @@ -82,7 +87,7 @@ private static string GetNameWithoutCache(ContextualAccessorInfo accessorInfo) /// The member info /// The XML Docs settings. /// The description or null if no description is available. - public static string GetDescription(this CachedType type, IXmlDocsSettings xmlDocsSettings) + public static string? GetDescription(this CachedType type, IXmlDocsSettings xmlDocsSettings) { var attributes = type is ContextualType contextualType ? contextualType.ContextAttributes : type.InheritedAttributes; @@ -108,7 +113,7 @@ public static string GetDescription(this CachedType type, IXmlDocsSettings xmlDo /// The accessor info. /// The XML Docs settings. /// The description or null if no description is available. - public static string GetDescription(this ContextualAccessorInfo accessorInfo, IXmlDocsSettings xmlDocsSettings) + public static string? GetDescription(this ContextualAccessorInfo accessorInfo, IXmlDocsSettings xmlDocsSettings) { var description = GetDescription(accessorInfo.AccessorType.Attributes); if (description != null) @@ -132,7 +137,7 @@ public static string GetDescription(this ContextualAccessorInfo accessorInfo, IX /// The parameter. /// The XML Docs settings. /// The description or null if no description is available. - public static string GetDescription(this ContextualParameterInfo parameter, IXmlDocsSettings xmlDocsSettings) + public static string? GetDescription(this ContextualParameterInfo parameter, IXmlDocsSettings xmlDocsSettings) { var description = GetDescription(parameter.ContextAttributes); if (description != null) @@ -152,16 +157,16 @@ public static string GetDescription(this ContextualParameterInfo parameter, IXml return null; } - private static string GetDescription(IEnumerable attributes) + private static string? GetDescription(IEnumerable attributes) { - dynamic descriptionAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DescriptionAttribute"); - if (descriptionAttribute != null && !string.IsNullOrEmpty(descriptionAttribute.Description)) + dynamic? descriptionAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DescriptionAttribute"); + if (descriptionAttribute != null && !string.IsNullOrEmpty(descriptionAttribute?.Description)) { - return descriptionAttribute.Description; + return descriptionAttribute!.Description; } else { - dynamic displayAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DisplayAttribute"); + dynamic? displayAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.DisplayAttribute"); if (displayAttribute != null) { // GetDescription returns null if the Description property on the attribute is not specified. diff --git a/src/NJsonSchema/Infrastructure/XmlObjectExtension.cs b/src/NJsonSchema/Infrastructure/XmlObjectExtension.cs index 7a73be02b..ff2ae3f6c 100644 --- a/src/NJsonSchema/Infrastructure/XmlObjectExtension.cs +++ b/src/NJsonSchema/Infrastructure/XmlObjectExtension.cs @@ -25,7 +25,7 @@ public static void GenerateXmlObjectForType(this JsonSchema schema, Type type) var attributes = type.ToCachedType().InheritedAttributes; if (attributes.Any()) { - dynamic xmlTypeAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); + dynamic? xmlTypeAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); if (xmlTypeAttribute != null) { GenerateXmlObject(xmlTypeAttribute.TypeName, xmlTypeAttribute.Namespace, false, false, schema); @@ -39,7 +39,7 @@ public static void GenerateXmlObjectForArrayType(this JsonSchema schema) { if (schema.IsArray && schema.ParentSchema == null) { - GenerateXmlObject($@"ArrayOf{schema.Item.Xml.Name}", null, true, false, schema); + GenerateXmlObject($@"ArrayOf{schema.Item?.Xml?.Name}", null, true, false, schema); } } @@ -50,7 +50,7 @@ public static void GenerateXmlObjectForItemType(this JsonSchema schema, CachedTy { // Is done all the time for XML to be able to get type name as the element name if not there was an attribute defined since earlier var attributes = type.InheritedAttributes; - dynamic xmlTypeAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); + dynamic? xmlTypeAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); var itemName = GetXmlItemName(type.OriginalType); if (xmlTypeAttribute != null) @@ -67,20 +67,20 @@ public static void GenerateXmlObjectForItemType(this JsonSchema schema, CachedTy /// The property name. public static void GenerateXmlObjectForProperty(this JsonSchemaProperty propertySchema, ContextualType type, string propertyName) { - string xmlName = null; - string xmlNamespace = null; + string? xmlName = null; + string? xmlNamespace = null; bool xmlWrapped = false; if (propertySchema.IsArray) { - dynamic xmlArrayAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayAttribute"); + dynamic? xmlArrayAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayAttribute"); if (xmlArrayAttribute != null) { xmlName = xmlArrayAttribute.ElementName; xmlNamespace = xmlArrayAttribute.Namespace; } - dynamic xmlArrayItemsAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayItemAttribute"); + dynamic? xmlArrayItemsAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayItemAttribute"); if (xmlArrayItemsAttribute != null) { var xmlItemName = xmlArrayItemsAttribute.ElementName; @@ -92,14 +92,14 @@ public static void GenerateXmlObjectForProperty(this JsonSchemaProperty property xmlWrapped = true; } - dynamic xmlElementAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlElementAttribute"); + dynamic? xmlElementAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlElementAttribute"); if (xmlElementAttribute != null) { xmlName = xmlElementAttribute.ElementName; xmlNamespace = xmlElementAttribute.Namespace; } - dynamic xmlAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlAttributeAttribute"); + dynamic? xmlAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlAttributeAttribute"); if (xmlAttribute != null) { if (!string.IsNullOrEmpty(xmlAttribute.AttributeName)) @@ -117,7 +117,7 @@ public static void GenerateXmlObjectForProperty(this JsonSchemaProperty property // We need to ensure that the property name is preserved if (string.IsNullOrEmpty(xmlName) && propertySchema.Type == JsonObjectType.None) { - dynamic xmlReferenceTypeAttribute = type.InheritedAttributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); + dynamic? xmlReferenceTypeAttribute = type.InheritedAttributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); if (xmlReferenceTypeAttribute != null) { xmlName = propertyName; @@ -130,7 +130,7 @@ public static void GenerateXmlObjectForProperty(this JsonSchemaProperty property } } - private static void GenerateXmlObject(string name, string @namespace, bool wrapped, bool isAttribute, JsonSchema schema) + private static void GenerateXmlObject(string? name, string? @namespace, bool wrapped, bool isAttribute, JsonSchema schema) { schema.Xml = new JsonXmlObject { diff --git a/src/NJsonSchema/JsonExtensionObject.cs b/src/NJsonSchema/JsonExtensionObject.cs index f18f50f0d..fdfaa286a 100644 --- a/src/NJsonSchema/JsonExtensionObject.cs +++ b/src/NJsonSchema/JsonExtensionObject.cs @@ -20,7 +20,7 @@ public class JsonExtensionObject : IJsonExtensionObject { /// Gets or sets the extension data (i.e. additional properties which are not directly defined by the JSON object). [JsonExtensionData] - public IDictionary ExtensionData { get; set; } + public IDictionary? ExtensionData { get; set; } } /// Deserializes all JSON Schemas in the extension data property. @@ -30,11 +30,11 @@ internal sealed class ExtensionDataDeserializationConverter : JsonConverter public override bool CanWrite => false; - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType != JsonToken.Null) { - var obj = (IJsonExtensionObject)Activator.CreateInstance(objectType); + var obj = (IJsonExtensionObject)Activator.CreateInstance(objectType)!; serializer.Populate(reader, obj); DeserializeExtensionDataSchemas(obj, serializer); return obj; @@ -51,7 +51,7 @@ public override bool CanConvert(Type objectType) return true; } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotImplementedException(); } @@ -70,7 +70,7 @@ internal void DeserializeExtensionDataSchemas(IJsonExtensionObject extensionObje } } - private object TryDeserializeValueSchemas(object value, JsonSerializer serializer) + private object? TryDeserializeValueSchemas(object? value, JsonSerializer serializer) { if (value is JObject obj) { @@ -87,7 +87,7 @@ private object TryDeserializeValueSchemas(object value, JsonSerializer serialize } } - var dictionary = new Dictionary(); + var dictionary = new Dictionary(); foreach (var property in obj.Properties()) { dictionary[property.Name] = TryDeserializeValueSchemas(property.Value, serializer); diff --git a/src/NJsonSchema/JsonPathUtilities.cs b/src/NJsonSchema/JsonPathUtilities.cs index a7a46e5bb..a335d4f5c 100644 --- a/src/NJsonSchema/JsonPathUtilities.cs +++ b/src/NJsonSchema/JsonPathUtilities.cs @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using Namotion.Reflection; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; @@ -26,7 +25,7 @@ public static class JsonPathUtilities /// The path or null when the object could not be found. /// Could not find the JSON path of a child object. /// is - public static string GetJsonPath(object rootObject, object searchedObject) + public static string? GetJsonPath(object rootObject, object searchedObject) { // TODO: Remove this overload? return GetJsonPath(rootObject, searchedObject, new DefaultContractResolver()); @@ -39,7 +38,7 @@ public static string GetJsonPath(object rootObject, object searchedObject) /// The path or null when the object could not be found. /// Could not find the JSON path of a child object. /// is - public static string GetJsonPath(object rootObject, object searchedObject, IContractResolver contractResolver) + public static string? GetJsonPath(object rootObject, object searchedObject, IContractResolver contractResolver) { return GetJsonPaths(rootObject, new List { searchedObject }, contractResolver)[searchedObject]; } @@ -51,7 +50,7 @@ public static string GetJsonPath(object rootObject, object searchedObject, ICont /// The path or null when the object could not be found. /// Could not find the JSON path of a child object. /// is - public static IReadOnlyDictionary GetJsonPaths(object rootObject, + public static IReadOnlyDictionary GetJsonPaths(object rootObject, IEnumerable searchedObjects, IContractResolver contractResolver) { if (rootObject == null) @@ -59,7 +58,7 @@ public static IReadOnlyDictionary GetJsonPaths(object rootObject throw new ArgumentNullException(nameof(rootObject)); } - var mappings = searchedObjects.ToDictionary(o => o, o => (string)null); + var mappings = searchedObjects.ToDictionary(o => o, o => (string?)null); FindJsonPaths(rootObject, mappings, "#", new HashSet(), contractResolver); if (mappings.Any(p => p.Value == null)) @@ -72,7 +71,7 @@ public static IReadOnlyDictionary GetJsonPaths(object rootObject return mappings; } - private static bool FindJsonPaths(object obj, Dictionary searchedObjects, + private static bool FindJsonPaths(object obj, Dictionary searchedObjects, string basePath, HashSet checkedObjects, IContractResolver contractResolver) { if (obj == null) @@ -108,7 +107,8 @@ private static bool FindJsonPaths(object obj, Dictionary searche { foreach (DictionaryEntry pair in dictionary) { - if (FindJsonPaths(pair.Value, searchedObjects, pathAndSeparator + pair.Key, checkedObjects, contractResolver)) + if (pair.Value != null && + FindJsonPaths(pair.Value, searchedObjects, pathAndSeparator + pair.Key, checkedObjects, contractResolver)) { return true; } @@ -119,7 +119,8 @@ private static bool FindJsonPaths(object obj, Dictionary searche for (var i = 0; i < list.Count; ++i) { var item = list[i]; - if (FindJsonPaths(item, searchedObjects, pathAndSeparator + i, checkedObjects, contractResolver)) + if (item != null && + FindJsonPaths(item, searchedObjects, pathAndSeparator + i, checkedObjects, contractResolver)) { return true; } @@ -130,7 +131,8 @@ private static bool FindJsonPaths(object obj, Dictionary searche var i = 0; foreach (var item in enumerable) { - if (FindJsonPaths(item, searchedObjects, pathAndSeparator + i, checkedObjects, contractResolver)) + if (item != null && + FindJsonPaths(item, searchedObjects, pathAndSeparator + i, checkedObjects, contractResolver)) { return true; } @@ -148,13 +150,11 @@ private static bool FindJsonPaths(object obj, Dictionary searche continue; } - var value = jsonProperty.ValueProvider.GetValue(obj); - if (value != null) + var value = jsonProperty.ValueProvider?.GetValue(obj); + if (value != null && + FindJsonPaths(value, searchedObjects, pathAndSeparator + jsonProperty.PropertyName, checkedObjects, contractResolver)) { - if (FindJsonPaths(value, searchedObjects, pathAndSeparator + jsonProperty.PropertyName, checkedObjects, contractResolver)) - { - return true; - } + return true; } } @@ -164,7 +164,8 @@ private static bool FindJsonPaths(object obj, Dictionary searche if (extensionDataProperty != null) { var value = extensionDataProperty.GetValue(obj); - if (FindJsonPaths(value, searchedObjects, basePath, checkedObjects, contractResolver)) + if (value != null && + FindJsonPaths(value, searchedObjects, basePath, checkedObjects, contractResolver)) { return true; } diff --git a/src/NJsonSchema/JsonReferenceResolver.cs b/src/NJsonSchema/JsonReferenceResolver.cs index d6fe7007f..543bf4070 100644 --- a/src/NJsonSchema/JsonReferenceResolver.cs +++ b/src/NJsonSchema/JsonReferenceResolver.cs @@ -9,6 +9,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; @@ -50,7 +51,7 @@ JsonReferenceResolver ReferenceResolverFactory(JsonSchema schema) => /// The referenced schema. public void AddDocumentReference(string documentPath, IJsonReference schema) { - _resolvedObjects[documentPath.Contains("://") ? documentPath : DynamicApis.GetFullPath(documentPath)] = schema; + _resolvedObjects[documentPath.Contains("://") ? documentPath : Path.GetFullPath(documentPath)] = schema; } /// Gets the object from the given JSON path. @@ -174,14 +175,14 @@ private async Task ResolveReferenceAsync(object rootObject, stri public virtual string ResolveFilePath(string documentPath, string jsonPath) { var arr = Regex.Split(jsonPath, @"(?=#)"); - return DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(documentPath), arr[0]); + return Path.Combine(Path.GetDirectoryName(documentPath)!, arr[0]); } private async Task ResolveFileReferenceWithAlreadyResolvedCheckAsync(string filePath, Type targetType, IContractResolver contractResolver, string jsonPath, bool append, CancellationToken cancellationToken) { try { - var fullPath = DynamicApis.GetFullPath(filePath); + var fullPath = Path.GetFullPath(filePath); var arr = Regex.Split(jsonPath, @"(?=#)"); fullPath = DynamicApis.HandleSubdirectoryRelativeReferences(fullPath, jsonPath); @@ -236,7 +237,7 @@ private async Task ResolveUrlReferenceWithAlreadyResolvedCheckAs } } - private IJsonReference ResolveDocumentReference(object obj, List segments, Type targetType, IContractResolver contractResolver, HashSet checkedObjects) + private IJsonReference? ResolveDocumentReference(object obj, List segments, Type targetType, IContractResolver contractResolver, HashSet checkedObjects) { if (obj == null || obj is string || checkedObjects.Contains(obj)) { @@ -259,7 +260,7 @@ private IJsonReference ResolveDocumentReference(object obj, List segment return ResolveDocumentReferenceWithoutDereferencing(obj, segments, targetType, contractResolver, checkedObjects); } - private IJsonReference ResolveDocumentReferenceWithoutDereferencing(object obj, List segments, Type targetType, IContractResolver contractResolver, HashSet checkedObjects) + private IJsonReference? ResolveDocumentReferenceWithoutDereferencing(object obj, List segments, Type targetType, IContractResolver contractResolver, HashSet checkedObjects) { if (segments.Count == 0) { @@ -267,11 +268,11 @@ private IJsonReference ResolveDocumentReferenceWithoutDereferencing(object obj, { var settings = new JsonSerializerSettings { ContractResolver = contractResolver }; var json = JsonConvert.SerializeObject(obj, settings); - return (IJsonReference)JsonConvert.DeserializeObject(json, targetType, settings); + return JsonConvert.DeserializeObject(json, targetType, settings) as IJsonReference; } else { - return (IJsonReference)obj; + return obj as IJsonReference; } } @@ -282,7 +283,7 @@ private IJsonReference ResolveDocumentReferenceWithoutDereferencing(object obj, { if (dictionary.Contains(firstSegment)) { - return ResolveDocumentReference(dictionary[firstSegment], segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); + return ResolveDocumentReference(dictionary[firstSegment]!, segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); } } else if (obj is IEnumerable) @@ -302,7 +303,7 @@ private IJsonReference ResolveDocumentReferenceWithoutDereferencing(object obj, var extensionObj = obj as IJsonExtensionObject; if (extensionObj?.ExtensionData?.ContainsKey(firstSegment) == true) { - return ResolveDocumentReference(extensionObj.ExtensionData[firstSegment], segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); + return ResolveDocumentReference(extensionObj.ExtensionData[firstSegment]!, segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); } foreach (var member in obj @@ -314,7 +315,10 @@ private IJsonReference ResolveDocumentReferenceWithoutDereferencing(object obj, if (pathSegment == firstSegment) { var value = member.GetValue(obj); - return ResolveDocumentReference(value, segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); + if (value != null) + { + return ResolveDocumentReference(value, segments.Skip(1).ToList(), targetType, contractResolver, checkedObjects); + } } } } diff --git a/src/NJsonSchema/JsonSchema.Reference.cs b/src/NJsonSchema/JsonSchema.Reference.cs index 267b1c93a..ee89538bd 100644 --- a/src/NJsonSchema/JsonSchema.Reference.cs +++ b/src/NJsonSchema/JsonSchema.Reference.cs @@ -20,7 +20,7 @@ public partial class JsonSchema : JsonReferenceBase, IJsonReference /// Cyclic references detected. /// The schema reference path has not been resolved. [JsonIgnore] - public virtual JsonSchema ActualSchema => GetActualSchema(null); + public virtual JsonSchema ActualSchema => GetActualSchema(new List()); /// Gets the type actual schema (e.g. the shared schema of a property, parameter, etc.). /// Cyclic references detected. @@ -93,7 +93,7 @@ static void ThrowInvalidOperationException(string message) throw new InvalidOperationException(message); } - if (checkedSchemas?.Contains(this) == true) + if (checkedSchemas.Contains(this) == true) { ThrowInvalidOperationException("Cyclic references detected."); } @@ -105,13 +105,13 @@ static void ThrowInvalidOperationException(string message) if (HasReference) { - return GetActualSchemaReferences(checkedSchemas); + return GetActualSchemaReferences(checkedSchemas) ?? this; } return this; } - private JsonSchema GetActualSchemaReferences(List checkedSchemas) + private JsonSchema? GetActualSchemaReferences(List checkedSchemas) { checkedSchemas ??= new List(); checkedSchemas.Add(this); @@ -131,7 +131,7 @@ private JsonSchema GetActualSchemaReferences(List checkedSchemas) return _anyOf[0].GetActualSchema(checkedSchemas); } - return Reference.GetActualSchema(checkedSchemas); + return Reference?.GetActualSchema(checkedSchemas); } #region Implementation of IJsonReference @@ -142,11 +142,11 @@ private JsonSchema GetActualSchemaReferences(List checkedSchemas) /// Gets the parent object of this object. [JsonIgnore] - object IJsonReference.PossibleRoot => Parent; + object? IJsonReference.PossibleRoot => Parent; /// Gets or sets the referenced object. [JsonIgnore] - public override JsonSchema Reference + public override JsonSchema? Reference { get { return base.Reference; } set diff --git a/src/NJsonSchema/JsonSchema.Serialization.cs b/src/NJsonSchema/JsonSchema.Serialization.cs index 46fe7473a..797bc9cbf 100644 --- a/src/NJsonSchema/JsonSchema.Serialization.cs +++ b/src/NJsonSchema/JsonSchema.Serialization.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.Serialization; using Namotion.Reflection; @@ -63,7 +64,7 @@ public static PropertyRenameAndIgnoreSerializerContractResolver CreateJsonSerial /// Gets or sets the extension data (i.e. additional properties which are not directly defined by JSON Schema). [JsonExtensionData] - public IDictionary ExtensionData { get; set; } + public IDictionary? ExtensionData { get; set; } [OnDeserialized] internal void OnDeserialized(StreamingContext ctx) @@ -73,11 +74,11 @@ internal void OnDeserialized(StreamingContext ctx) /// Gets the discriminator property (Swagger only). [JsonIgnore] - public string ActualDiscriminator => ActualTypeSchema.Discriminator; + public string? ActualDiscriminator => ActualTypeSchema.Discriminator; /// Gets or sets the discriminator property (Swagger only, should not be used in internal tooling). [JsonIgnore] - public string Discriminator + public string? Discriminator { get => DiscriminatorObject?.PropertyName; set @@ -98,15 +99,15 @@ public string Discriminator /// Gets the actual resolved discriminator of this schema (no inheritance, OpenApi only). [JsonIgnore] - public OpenApiDiscriminator ActualDiscriminatorObject => DiscriminatorObject ?? ActualTypeSchema.DiscriminatorObject; + public OpenApiDiscriminator? ActualDiscriminatorObject => DiscriminatorObject ?? ActualTypeSchema.DiscriminatorObject; /// Gets or sets the discriminator of this schema (OpenApi only). [JsonIgnore] - public OpenApiDiscriminator DiscriminatorObject { get; set; } + public OpenApiDiscriminator? DiscriminatorObject { get; set; } /// Gets or sets the discriminator. [JsonProperty("discriminator", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, Order = -100 + 5)] - internal object DiscriminatorRaw + internal object? DiscriminatorRaw { get { @@ -138,7 +139,7 @@ internal object DiscriminatorRaw /// Gets or sets a value indicating whether the maximum value is excluded. [JsonProperty("exclusiveMaximum", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal object ExclusiveMaximumRaw + internal object? ExclusiveMaximumRaw { get { return ExclusiveMaximum ?? (IsExclusiveMaximum ? (object)true : null); } set @@ -160,7 +161,7 @@ internal object ExclusiveMaximumRaw /// Gets or sets a value indicating whether the minimum value is excluded. [JsonProperty("exclusiveMinimum", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal object ExclusiveMinimumRaw + internal object? ExclusiveMinimumRaw { get { return ExclusiveMinimum ?? (IsExclusiveMinimum ? (object)true : null); } set @@ -181,7 +182,7 @@ internal object ExclusiveMinimumRaw } [JsonProperty("additionalItems", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal object AdditionalItemsRaw + internal object? AdditionalItemsRaw { get { @@ -215,7 +216,7 @@ internal object AdditionalItemsRaw } [JsonProperty("additionalProperties", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal object AdditionalPropertiesRaw + internal object? AdditionalPropertiesRaw { get { @@ -269,7 +270,7 @@ internal object AdditionalPropertiesRaw } [JsonProperty("items", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal object ItemsRaw + internal object? ItemsRaw { get { @@ -298,14 +299,14 @@ internal object ItemsRaw } } - private Lazy _typeRaw; + private Lazy? _typeRaw; [JsonProperty("type", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, Order = -100 + 3)] - internal object TypeRaw + internal object? TypeRaw { get { - if (_typeRaw == null) + if (_typeRaw is null) { ResetTypeRaw(); } @@ -327,9 +328,10 @@ internal object TypeRaw } } + [MemberNotNull(nameof(_typeRaw))] private void ResetTypeRaw() { - _typeRaw = new Lazy(() => + _typeRaw = new Lazy(() => { var flags = _jsonObjectTypeValues .Where(v => Type.HasFlag(v)) @@ -350,26 +352,26 @@ private void ResetTypeRaw() } [JsonProperty("required", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal ICollection RequiredPropertiesRaw + internal ICollection? RequiredPropertiesRaw { get { return RequiredProperties != null && RequiredProperties.Count > 0 ? RequiredProperties : null; } - set { RequiredProperties = value; } + set { RequiredProperties = value ?? new List(); } } [JsonProperty("properties", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal IDictionary PropertiesRaw + internal IDictionary? PropertiesRaw { get => _properties != null && _properties.Count > 0 ? Properties : null; set { Properties = value != null ? - new ObservableDictionary(value) : + new ObservableDictionary(value!) : new ObservableDictionary(); } } [JsonProperty("patternProperties", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal IDictionary PatternPropertiesRaw + internal IDictionary? PatternPropertiesRaw { get { @@ -379,55 +381,55 @@ internal IDictionary PatternPropertiesRaw set { PatternProperties = value != null ? - new ObservableDictionary(value) : + new ObservableDictionary(value!) : new ObservableDictionary(); } } [JsonProperty("definitions", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal IDictionary DefinitionsRaw + internal IDictionary? DefinitionsRaw { get { return Definitions != null && Definitions.Count > 0 ? Definitions : null; } - set { Definitions = value != null ? new ObservableDictionary(value) : new ObservableDictionary(); } + set { Definitions = value != null ? new ObservableDictionary(value!) : new ObservableDictionary(); } } /// Gets or sets the enumeration names (optional, draft v5). [JsonProperty("x-enumNames", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal Collection EnumerationNamesRaw + internal Collection? EnumerationNamesRaw { get { return EnumerationNames != null && EnumerationNames.Count > 0 ? EnumerationNames : null; } set { EnumerationNames = value != null ? new ObservableCollection(value) : new ObservableCollection(); } } [JsonProperty("enum", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal ICollection EnumerationRaw + internal ICollection? EnumerationRaw { get { return Enumeration != null && Enumeration.Count > 0 ? Enumeration : null; } - set { Enumeration = value != null ? new ObservableCollection(value) : new ObservableCollection(); } + set { Enumeration = value != null ? new ObservableCollection(value) : new ObservableCollection(); } } [JsonProperty("allOf", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal ICollection AllOfRaw + internal ICollection? AllOfRaw { get { return _allOf != null && _allOf.Count > 0 ? AllOf : null; } set { AllOf = value != null ? new ObservableCollection(value) : new ObservableCollection(); } } [JsonProperty("anyOf", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal ICollection AnyOfRaw + internal ICollection? AnyOfRaw { get { return _anyOf != null && _anyOf.Count > 0 ? AnyOf : null; } set { AnyOf = value != null ? new ObservableCollection(value) : new ObservableCollection(); } } [JsonProperty("oneOf", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - internal ICollection OneOfRaw + internal ICollection? OneOfRaw { get { return _oneOf != null && _oneOf.Count > 0 ? OneOf : null; } set { OneOf = value != null ? new ObservableCollection(value) : new ObservableCollection(); } } - private void RegisterProperties(ObservableDictionary oldCollection, ObservableDictionary newCollection) + private void RegisterProperties(ObservableDictionary? oldCollection, ObservableDictionary? newCollection) { if (oldCollection != null) { @@ -441,7 +443,7 @@ private void RegisterProperties(ObservableDictionary } } - private void RegisterSchemaDictionary(ObservableDictionary oldCollection, ObservableDictionary newCollection) + private void RegisterSchemaDictionary(ObservableDictionary? oldCollection, ObservableDictionary? newCollection) where T : JsonSchema { if (oldCollection != null) @@ -456,7 +458,7 @@ private void RegisterSchemaDictionary(ObservableDictionary oldColl } } - private void RegisterSchemaCollection(ObservableCollection oldCollection, ObservableCollection newCollection) + private void RegisterSchemaCollection(ObservableCollection? oldCollection, ObservableCollection? newCollection) { if (oldCollection != null) { @@ -470,13 +472,13 @@ private void RegisterSchemaCollection(ObservableCollection oldCollec } } - private void InitializeSchemaCollection(object sender, NotifyCollectionChangedEventArgs e) + private void InitializeSchemaCollection(object? sender, NotifyCollectionChangedEventArgs? args) { if (sender is ObservableDictionary properties) { foreach (var property in properties) { - property.Value.Name = property.Key; + property.Value!.Name = property.Key; property.Value.Parent = this; } } diff --git a/src/NJsonSchema/JsonSchema.cs b/src/NJsonSchema/JsonSchema.cs index 954800147..3eb472c2e 100644 --- a/src/NJsonSchema/JsonSchema.cs +++ b/src/NJsonSchema/JsonSchema.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -41,18 +42,18 @@ public partial class JsonSchema : IDocumentPathProvider internal ObservableCollection _allOf; internal ObservableCollection _anyOf; internal ObservableCollection _oneOf; - private JsonSchema _not; - private JsonSchema _dictionaryKey; + private JsonSchema? _not; + private JsonSchema? _dictionaryKey; private JsonObjectType _type; - private JsonSchema _item; + private JsonSchema? _item; internal ObservableCollection _items; private bool _allowAdditionalItems = true; - private JsonSchema _additionalItemsSchema = null; + private JsonSchema? _additionalItemsSchema = null; private bool _allowAdditionalProperties = true; - private JsonSchema _additionalPropertiesSchema = null; + private JsonSchema? _additionalPropertiesSchema = null; /// Initializes a new instance of the class. public JsonSchema() @@ -157,7 +158,7 @@ public static Task FromJsonAsync(Stream stream, CancellationToken ca /// The document path (URL or file path) for resolving relative document references. /// The cancellation token /// The JSON Schema. - public static Task FromJsonAsync(string data, string documentPath, CancellationToken cancellationToken = default) + public static Task FromJsonAsync(string data, string? documentPath, CancellationToken cancellationToken = default) { var factory = JsonReferenceResolver.CreateJsonReferenceResolverFactory(new DefaultTypeNameGenerator()); return FromJsonAsync(data, documentPath, factory, cancellationToken); @@ -169,7 +170,7 @@ public static Task FromJsonAsync(string data, string documentPath, C /// The JSON reference resolver factory. /// The cancellation token /// The JSON Schema. - public static Task FromJsonAsync(string data, string documentPath, Func FromJsonAsync(string data, string? documentPath, Func referenceResolverFactory, CancellationToken cancellationToken = default) { return JsonSchemaSerialization.FromJsonAsync(data, SerializationSchemaType, documentPath, referenceResolverFactory, ContractResolver.Value, cancellationToken); @@ -181,7 +182,7 @@ public static Task FromJsonAsync(string data, string documentPath, F /// The JSON reference resolver factory. /// The cancellation token /// The JSON Schema. - public static Task FromJsonAsync(Stream stream, string documentPath, Func FromJsonAsync(Stream stream, string? documentPath, Func referenceResolverFactory, CancellationToken cancellationToken = default) { return JsonSchemaSerialization.FromJsonAsync(stream, SerializationSchemaType, documentPath, referenceResolverFactory, ContractResolver.Value, cancellationToken); @@ -237,7 +238,7 @@ public static JsonSchema FromSampleJson(string data) internal static JsonSchema FromJsonWithCurrentSettings(object obj) { var json = JsonConvert.SerializeObject(obj, JsonSchemaSerialization.CurrentSerializerSettings); - return JsonConvert.DeserializeObject(json, JsonSchemaSerialization.CurrentSerializerSettings); + return JsonConvert.DeserializeObject(json, JsonSchemaSerialization.CurrentSerializerSettings)!; } /// Gets a value indicating whether the schema is binary (file or binary format). @@ -254,7 +255,7 @@ public bool IsBinary /// Gets the inherited/parent schema (most probable base schema in allOf). /// Used for code generation. [JsonIgnore] - public JsonSchema InheritedSchema + public JsonSchema? InheritedSchema { get { @@ -288,7 +289,7 @@ public JsonSchema InheritedSchema /// (the schema itself if it is a dictionary or array, otherwise ). /// Used for code generation. [JsonIgnore] - public JsonSchema InheritedTypeSchema + public JsonSchema? InheritedTypeSchema { get { @@ -327,7 +328,7 @@ public bool Inherits(JsonSchema schema) /// Gets the discriminator or discriminator of an inherited schema (or null). [JsonIgnore] - public OpenApiDiscriminator ResponsibleDiscriminatorObject => + public OpenApiDiscriminator? ResponsibleDiscriminatorObject => ActualDiscriminatorObject ?? InheritedSchema?.ActualSchema.ResponsibleDiscriminatorObject; /// @@ -395,15 +396,15 @@ public IReadOnlyDictionary ActualProperties /// Gets or sets the schema. [JsonProperty("$schema", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, Order = -100 + 1)] - public string SchemaVersion { get; set; } + public string? SchemaVersion { get; set; } /// Gets or sets the id. [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, Order = -100 + 2)] - public string Id { get; set; } + public string? Id { get; set; } /// Gets or sets the title. [JsonProperty("title", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, Order = -100 + 3)] - public string Title { get; set; } + public string? Title { get; set; } /// Gets a value indicating whether the schema title can be used as type name. [JsonIgnore] @@ -411,7 +412,7 @@ public IReadOnlyDictionary ActualProperties /// Gets or sets the description. [JsonProperty("description", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public virtual string Description { get; set; } + public virtual string? Description { get; set; } /// Gets the object types (as enum flags). [JsonIgnore] @@ -426,19 +427,19 @@ public JsonObjectType Type /// Gets the parent schema of this schema. [JsonIgnore] - public JsonSchema ParentSchema => Parent as JsonSchema; + public JsonSchema? ParentSchema => Parent as JsonSchema; /// Gets the parent schema of this schema. [JsonIgnore] - public virtual object Parent { get; set; } + public virtual object? Parent { get; set; } /// Gets or sets the format string. [JsonProperty("format", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string Format { get; set; } + public string? Format { get; set; } /// Gets or sets the default value. [JsonProperty("default", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public object Default { get; set; } + public object? Default { get; set; } /// Gets or sets the required multiple of for the number value. [JsonProperty("multipleOf", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -478,7 +479,7 @@ public JsonObjectType Type /// Gets or sets the validation pattern as regular expression. [JsonProperty("pattern", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string Pattern { get; set; } + public string? Pattern { get; set; } /// Gets or sets the maximum length of the array. [JsonProperty("maxItems", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -506,7 +507,7 @@ public JsonObjectType Type /// Gets or sets a message indicating why the schema is deprecated (custom extension, sets 'x-deprecatedMessage'). [JsonProperty("x-deprecatedMessage", DefaultValueHandling = DefaultValueHandling.Ignore)] - public string DeprecatedMessage { get; set; } + public string? DeprecatedMessage { get; set; } /// Gets or sets a value indicating whether the type is abstract, i.e. cannot be instantiated directly (x-abstract). [JsonProperty("x-abstract", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -518,7 +519,7 @@ public JsonObjectType Type /// Gets or sets the example (Swagger and Open API only). [JsonProperty("x-example", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public object Example { get; set; } + public object? Example { get; set; } /// Gets or sets a value indicating this is an bit flag enum (custom extension, sets 'x-enumFlags', default: false). [JsonProperty("x-enumFlags", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -526,7 +527,7 @@ public JsonObjectType Type /// Gets the collection of required properties. [JsonIgnore] - public ICollection Enumeration { get; internal set; } + public ICollection Enumeration { get; internal set; } /// Gets a value indicating whether this is enumeration. [JsonIgnore] @@ -541,7 +542,7 @@ public JsonObjectType Type /// Gets or sets the dictionary key schema (x-dictionaryKey, only enum schemas are allowed). [JsonProperty("x-dictionaryKey", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public JsonSchema DictionaryKey + public JsonSchema? DictionaryKey { get { return _dictionaryKey; } set @@ -572,7 +573,7 @@ internal set /// Gets the xml object of the schema (used in Swagger specifications). [JsonProperty("xml", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public JsonXmlObject Xml + public JsonXmlObject? Xml { get { return _xmlObject; } set @@ -587,7 +588,7 @@ public JsonXmlObject Xml } [JsonIgnore] - private JsonXmlObject _xmlObject; + private JsonXmlObject? _xmlObject; /// Gets the pattern properties of the type. [JsonIgnore] @@ -607,7 +608,7 @@ internal set /// Gets or sets the schema of an array item. [JsonIgnore] - public JsonSchema Item + public JsonSchema? Item { get { return _item; } set @@ -647,7 +648,7 @@ internal set /// Gets or sets the schema which must not be valid. [JsonProperty("not", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public JsonSchema Not + public JsonSchema? Not { get { return _not; } set @@ -746,7 +747,7 @@ public bool AllowAdditionalItems /// Gets or sets the schema for the additional items. /// If this property has a schema, then is set to true. [JsonIgnore] - public JsonSchema AdditionalItemsSchema + public JsonSchema? AdditionalItemsSchema { get { return _additionalItemsSchema; } set @@ -784,7 +785,7 @@ public bool AllowAdditionalProperties /// Gets or sets the schema for the additional properties. /// If this property has a schema, then is set to true. [JsonIgnore] - public JsonSchema AdditionalPropertiesSchema + public JsonSchema? AdditionalPropertiesSchema { get { return _additionalPropertiesSchema; } set @@ -872,7 +873,7 @@ public virtual bool IsNullable(SchemaType schemaType) if (ExtensionData != null && ExtensionData.TryGetValue("nullable", out var value)) { - if (bool.TryParse(value.ToString(), out var boolValue)) + if (bool.TryParse(value?.ToString(), out var boolValue)) { return boolValue; } @@ -939,7 +940,7 @@ public bool InheritsSchema(JsonSchema parentSchema) /// The validator settings. /// Could not deserialize the JSON data. /// The collection of validation errors. - public ICollection Validate(string jsonData, JsonSchemaValidatorSettings settings = null) + public ICollection Validate(string jsonData, JsonSchemaValidatorSettings? settings = null) { var validator = new JsonSchemaValidator(settings); return validator.Validate(jsonData, ActualSchema); @@ -948,7 +949,7 @@ public ICollection Validate(string jsonData, JsonSchemaValidato /// The token to validate. /// The validator settings. /// The collection of validation errors. - public ICollection Validate(JToken token, JsonSchemaValidatorSettings settings = null) + public ICollection Validate(JToken token, JsonSchemaValidatorSettings? settings = null) { var validator = new JsonSchemaValidator(settings); return validator.Validate(token, ActualSchema); @@ -960,7 +961,7 @@ public ICollection Validate(JToken token, JsonSchemaValidatorSe /// The validator settings. /// Could not deserialize the JSON data. /// The collection of validation errors. - public ICollection Validate(string jsonData, SchemaType schemaType, JsonSchemaValidatorSettings settings = null) + public ICollection Validate(string jsonData, SchemaType schemaType, JsonSchemaValidatorSettings? settings = null) { var validator = new JsonSchemaValidator(settings); return validator.Validate(jsonData, ActualSchema, schemaType); @@ -971,13 +972,13 @@ public ICollection Validate(string jsonData, SchemaType schemaT /// The type of the schema. /// The validator settings. /// The collection of validation errors. - public ICollection Validate(JToken token, SchemaType schemaType, JsonSchemaValidatorSettings settings = null) + public ICollection Validate(JToken token, SchemaType schemaType, JsonSchemaValidatorSettings? settings = null) { var validator = new JsonSchemaValidator(settings); return validator.Validate(token, ActualSchema, schemaType); } - private static JsonObjectType ConvertStringToJsonObjectType(string value) + private static JsonObjectType ConvertStringToJsonObjectType(string? value) { // Section 3.5: // http://json-schema.org/latest/json-schema-core.html#anchor8 @@ -1006,7 +1007,25 @@ private static JsonObjectType ConvertStringToJsonObjectType(string value) } } + [MemberNotNull(nameof(Items))] + [MemberNotNull(nameof(_items))] + [MemberNotNull(nameof(Properties))] + [MemberNotNull(nameof(_properties))] + [MemberNotNull(nameof(PatternProperties))] + [MemberNotNull(nameof(_patternProperties))] + [MemberNotNull(nameof(Definitions))] + [MemberNotNull(nameof(_definitions))] + [MemberNotNull(nameof(RequiredProperties))] + [MemberNotNull(nameof(AllOf))] + [MemberNotNull(nameof(_allOf))] + [MemberNotNull(nameof(AnyOf))] + [MemberNotNull(nameof(_anyOf))] + [MemberNotNull(nameof(OneOf))] + [MemberNotNull(nameof(_oneOf))] + [MemberNotNull(nameof(Enumeration))] + [MemberNotNull(nameof(EnumerationNames))] private void Initialize() +#pragma warning disable CS8774 { if (Items == null) { @@ -1030,7 +1049,7 @@ private void Initialize() if (RequiredProperties == null) { - RequiredProperties = new ObservableCollection(); + RequiredProperties = new Collection(); } if (AllOf == null) @@ -1050,7 +1069,7 @@ private void Initialize() if (Enumeration == null) { - Enumeration = new Collection(); + Enumeration = new Collection(); } if (EnumerationNames == null) @@ -1058,23 +1077,16 @@ private void Initialize() EnumerationNames = new Collection(); } } +#pragma warning restore CS8774 private static ObservableCollection ToObservableCollection(ICollection value) { - if (value is null) - { - return null; - } return value as ObservableCollection ?? new ObservableCollection(value); } private static ObservableDictionary ToObservableDictionary(IDictionary value) { - if (value is null) - { - return null; - } - return value as ObservableDictionary ?? new ObservableDictionary(value); + return value as ObservableDictionary ?? new ObservableDictionary(value!); } } } diff --git a/src/NJsonSchema/JsonSchemaAppender.cs b/src/NJsonSchema/JsonSchemaAppender.cs index 019b073e0..d2331e9db 100644 --- a/src/NJsonSchema/JsonSchemaAppender.cs +++ b/src/NJsonSchema/JsonSchemaAppender.cs @@ -35,7 +35,7 @@ public JsonSchemaAppender(object rootObject, ITypeNameGenerator typeNameGenerato /// The type name hint. /// is /// The root schema cannot be appended. - public virtual void AppendSchema(JsonSchema schema, string typeNameHint) + public virtual void AppendSchema(JsonSchema schema, string? typeNameHint) { if (schema == null) { diff --git a/src/NJsonSchema/JsonSchemaProperty.cs b/src/NJsonSchema/JsonSchemaProperty.cs index 129a44db2..2737678a1 100644 --- a/src/NJsonSchema/JsonSchemaProperty.cs +++ b/src/NJsonSchema/JsonSchemaProperty.cs @@ -14,15 +14,17 @@ namespace NJsonSchema /// A description of a JSON property of a JSON schema. public class JsonSchemaProperty : JsonSchema { - private object _parent; + private object? _parent; /// Gets or sets the name of the property. [JsonIgnore] +#pragma warning disable CS8618 public string Name { get; internal set; } +#pragma warning restore CS8618 /// Gets the parent schema of this property schema. [JsonIgnore] - public override object Parent + public override object? Parent { get { return _parent; } set @@ -41,7 +43,7 @@ public override object Parent [JsonIgnore] public bool IsRequired { - get { return ParentSchema.RequiredProperties.Contains(Name); } + get { return ParentSchema!.RequiredProperties.Contains(Name); } set { if (ParentSchema == null) @@ -84,7 +86,7 @@ public bool IsRequired /// Gets a value indicating whether the property is an inheritance discriminator. [JsonIgnore] - public bool IsInheritanceDiscriminator => ParentSchema.ActualDiscriminator == Name; + public bool IsInheritanceDiscriminator => ParentSchema!.ActualDiscriminator == Name; /// Determines whether the specified property null handling is nullable. /// The schema type. diff --git a/src/NJsonSchema/JsonSchemaReferenceUtilities.cs b/src/NJsonSchema/JsonSchemaReferenceUtilities.cs index bbcac37ef..c29941498 100644 --- a/src/NJsonSchema/JsonSchemaReferenceUtilities.cs +++ b/src/NJsonSchema/JsonSchemaReferenceUtilities.cs @@ -93,7 +93,7 @@ public override async Task VisitAsync(object obj, CancellationToken cancellation await base.VisitAsync(obj, cancellationToken).ConfigureAwait(false); } - protected override async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint, CancellationToken cancellationToken) + protected override async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string? typeNameHint, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (reference.ReferencePath != null && reference.Reference == null) @@ -137,7 +137,7 @@ public JsonReferencePathUpdater(object rootObject, DictionaryGets the parent schema of the XML object schema. [JsonIgnore] - public JsonSchema ParentSchema { get; internal set; } + public JsonSchema? ParentSchema { get; internal set; } /// Gets or sets the name of the xml object. [JsonProperty("name", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string Name { get; internal set; } + public string? Name { get; internal set; } /// Gets or sets if the array elements are going to be wrapped or not. [JsonProperty("wrapped", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -27,11 +27,11 @@ public class JsonXmlObject /// Gets or sets the URL of the namespace definition. [JsonProperty("namespace", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string Namespace { get; internal set; } + public string? Namespace { get; internal set; } /// Gets or sets the prefix for the name. [JsonProperty("prefix", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string Prefix { get; internal set; } + public string? Prefix { get; internal set; } /// Gets or sets if the property definition translates into an attribute instead of an element. [JsonProperty("attribute", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] diff --git a/src/NJsonSchema/OpenApiDiscriminator.cs b/src/NJsonSchema/OpenApiDiscriminator.cs index e0e9cf473..40e782615 100644 --- a/src/NJsonSchema/OpenApiDiscriminator.cs +++ b/src/NJsonSchema/OpenApiDiscriminator.cs @@ -20,7 +20,7 @@ public class OpenApiDiscriminator { /// Gets or sets the discriminator property name. [JsonProperty("propertyName", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public string PropertyName { get; set; } + public string? PropertyName { get; set; } /// Gets or sets the discriminator mappings. [JsonProperty("mapping", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -29,7 +29,7 @@ public class OpenApiDiscriminator /// The currently used . [JsonIgnore] - public object JsonInheritanceConverter { get; set; } + public object? JsonInheritanceConverter { get; set; } /// Adds a discriminator mapping for the given type and schema based on the used . /// The type. @@ -41,7 +41,7 @@ public void AddMapping(Type type, JsonSchema schema) if (getDiscriminatorValueMethod != null) { - var discriminatorValue = (string)getDiscriminatorValueMethod.Invoke(JsonInheritanceConverter, new[] { type } ); + var discriminatorValue = (string)getDiscriminatorValueMethod.Invoke(JsonInheritanceConverter, new[] { type } )!; Mapping[discriminatorValue] = new JsonSchema { Reference = schema.ActualSchema }; } else @@ -62,7 +62,7 @@ public override bool CanConvert(Type objectType) return true; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var openApiMapping = serializer.Deserialize>(reader); if (openApiMapping != null && existingValue != null) @@ -81,7 +81,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return existingValue; } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { var internalMapping = value as IDictionary; if (internalMapping != null) @@ -89,7 +89,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s var openApiMapping = new Dictionary(); foreach (var tuple in internalMapping) { - openApiMapping[tuple.Key] = ((IJsonReferenceBase)tuple.Value).ReferencePath; + openApiMapping[tuple.Key] = ((IJsonReferenceBase)tuple.Value).ReferencePath!; } var jObject = JObject.FromObject(openApiMapping, serializer); @@ -97,7 +97,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } else { - writer.WriteValue((string)null); + writer.WriteValue((string?)null); } } } diff --git a/src/NJsonSchema/References/IJsonReference.cs b/src/NJsonSchema/References/IJsonReference.cs index 877f37af3..a728c69b0 100644 --- a/src/NJsonSchema/References/IJsonReference.cs +++ b/src/NJsonSchema/References/IJsonReference.cs @@ -20,6 +20,6 @@ public interface IJsonReference : IJsonReferenceBase /// Gets the parent object which may be the root. [JsonIgnore] - object PossibleRoot { get; } + object? PossibleRoot { get; } } } \ No newline at end of file diff --git a/src/NJsonSchema/References/IJsonReferenceBase.cs b/src/NJsonSchema/References/IJsonReferenceBase.cs index 669ad35f0..0b255ef5d 100644 --- a/src/NJsonSchema/References/IJsonReferenceBase.cs +++ b/src/NJsonSchema/References/IJsonReferenceBase.cs @@ -15,10 +15,10 @@ public interface IJsonReferenceBase : IDocumentPathProvider { /// Gets or sets the type reference path ($ref). [JsonProperty("$ref", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - string ReferencePath { get; set; } + string? ReferencePath { get; set; } /// Gets or sets the referenced object. [JsonIgnore] - IJsonReference Reference { get; set; } + IJsonReference? Reference { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema/References/JsonReferenceBase.cs b/src/NJsonSchema/References/JsonReferenceBase.cs index 994858394..668bbc4b1 100644 --- a/src/NJsonSchema/References/JsonReferenceBase.cs +++ b/src/NJsonSchema/References/JsonReferenceBase.cs @@ -16,19 +16,19 @@ namespace NJsonSchema.References public abstract class JsonReferenceBase : IJsonReferenceBase where T : class, IJsonReference { - private T _reference; + private T? _reference; /// Gets the document path (URI or file path) for resolving relative references. [JsonIgnore] - public string DocumentPath { get; set; } + public string? DocumentPath { get; set; } /// Gets or sets the type reference path ($ref). [JsonProperty("$ref", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - string IJsonReferenceBase.ReferencePath { get; set; } + string? IJsonReferenceBase.ReferencePath { get; set; } /// Gets or sets the referenced object. [JsonIgnore] - public virtual T Reference + public virtual T? Reference { get => _reference; set @@ -43,10 +43,10 @@ public virtual T Reference /// Gets or sets the referenced object. [JsonIgnore] - IJsonReference IJsonReferenceBase.Reference + IJsonReference? IJsonReferenceBase.Reference { get => Reference; - set => Reference = (T)value; + set => Reference = (T?)value; } } } \ No newline at end of file diff --git a/src/NJsonSchema/References/JsonReferenceExtensions.cs b/src/NJsonSchema/References/JsonReferenceExtensions.cs index 11fefea84..4c25c230f 100644 --- a/src/NJsonSchema/References/JsonReferenceExtensions.cs +++ b/src/NJsonSchema/References/JsonReferenceExtensions.cs @@ -13,7 +13,7 @@ public static class JsonReferenceExtensions { /// Finds the root parent of this schema. /// The parent schema or this when this is the root. - public static object FindParentDocument(this IJsonReference obj) + public static object? FindParentDocument(this IJsonReference obj) { if (obj.DocumentPath != null) { @@ -28,7 +28,7 @@ public static object FindParentDocument(this IJsonReference obj) while ((parent as IJsonReference)?.PossibleRoot != null) { - parent = ((IJsonReference)parent).PossibleRoot; + parent = ((IJsonReference)parent!).PossibleRoot; if (parent is IDocumentPathProvider pathProvider && pathProvider.DocumentPath != null) { return parent; diff --git a/src/NJsonSchema/SampleJsonSchemaGenerator.cs b/src/NJsonSchema/SampleJsonSchemaGenerator.cs index 534ccfe03..37a7c51c1 100644 --- a/src/NJsonSchema/SampleJsonSchemaGenerator.cs +++ b/src/NJsonSchema/SampleJsonSchemaGenerator.cs @@ -27,7 +27,7 @@ public JsonSchema Generate(string json) var token = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.IsoDateFormat - }); + })!; var schema = new JsonSchema(); Generate(token, schema, schema, "Anonymous"); @@ -47,7 +47,7 @@ public JsonSchema Generate(Stream stream) DateFormatHandling = DateFormatHandling.IsoDateFormat }); - var token = serializer.Deserialize(jsonReader); + var token = serializer.Deserialize(jsonReader)!; var schema = new JsonSchema(); Generate(token, schema, schema, "Anonymous"); @@ -58,7 +58,7 @@ private void Generate(JToken token, JsonSchema schema, JsonSchema rootSchema, st { if (schema != rootSchema && token.Type == JTokenType.Object) { - JsonSchema referencedSchema = null; + JsonSchema? referencedSchema = null; if (token is JObject obj) { var properties = obj.Properties(); @@ -145,17 +145,17 @@ private void GenerateWithoutReference(JToken token, JsonSchema schema, JsonSchem break; } - if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value(), "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$")) + if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value()!, "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$")) { schema.Format = JsonFormatStrings.Date; } - if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value(), "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$")) + if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value()!, "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$")) { schema.Format = JsonFormatStrings.DateTime; } - if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value(), "^[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$")) + if (schema.Type == JsonObjectType.String && Regex.IsMatch(token.Value()!, "^[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$")) { schema.Format = JsonFormatStrings.Duration; } diff --git a/src/NJsonSchema/Validation/ChildSchemaValidationError.cs b/src/NJsonSchema/Validation/ChildSchemaValidationError.cs index e296e609a..dc9e54b8d 100644 --- a/src/NJsonSchema/Validation/ChildSchemaValidationError.cs +++ b/src/NJsonSchema/Validation/ChildSchemaValidationError.cs @@ -21,7 +21,7 @@ public class ChildSchemaValidationError : ValidationError /// The error list. /// The token that failed to validate. /// The schema that contains the validation rule. - public ChildSchemaValidationError(ValidationErrorKind kind, string property, string path, IReadOnlyDictionary> errors, JToken token, JsonSchema schema) + public ChildSchemaValidationError(ValidationErrorKind kind, string? property, string? path, IReadOnlyDictionary> errors, JToken token, JsonSchema schema) : base(kind, property, path, token, schema) { Errors = errors; diff --git a/src/NJsonSchema/Validation/FormatValidators/UriFormatValidator.cs b/src/NJsonSchema/Validation/FormatValidators/UriFormatValidator.cs index dc1863054..a118830af 100644 --- a/src/NJsonSchema/Validation/FormatValidators/UriFormatValidator.cs +++ b/src/NJsonSchema/Validation/FormatValidators/UriFormatValidator.cs @@ -26,8 +26,8 @@ public class UriFormatValidator : IFormatValidator /// True if value is correct for given format, False - if not. public bool IsValid(string value, JTokenType tokenType) { - return tokenType == JTokenType.Uri - || Uri.TryCreate(value, UriKind.Absolute, out Uri uriResult); + return tokenType == JTokenType.Uri || + Uri.TryCreate(value, UriKind.Absolute, out Uri? _); } } } diff --git a/src/NJsonSchema/Validation/JsonSchemaValidator.cs b/src/NJsonSchema/Validation/JsonSchemaValidator.cs index ba88b40f9..2e6963011 100644 --- a/src/NJsonSchema/Validation/JsonSchemaValidator.cs +++ b/src/NJsonSchema/Validation/JsonSchemaValidator.cs @@ -34,7 +34,7 @@ public JsonSchemaValidator(params IFormatValidator[] customValidators) /// /// Initializes JsonSchemaValidator /// - public JsonSchemaValidator(JsonSchemaValidatorSettings settings) + public JsonSchemaValidator(JsonSchemaValidatorSettings? settings) { _settings = settings ?? new JsonSchemaValidatorSettings(); _formatValidatorsMap = _settings.FormatValidators.GroupBy(x => x.Format).ToDictionary(v => v.Key, v => v.ToArray()); @@ -76,7 +76,7 @@ public ICollection Validate(JToken token, JsonSchema schema, Sc /// The current property name. /// The current property path. /// The list of validation errors. - protected virtual ICollection Validate(JToken token, JsonSchema schema, SchemaType schemaType, string propertyName, string propertyPath) + protected virtual ICollection Validate(JToken token, JsonSchema schema, SchemaType schemaType, string? propertyName, string propertyPath) { var errors = new List(); @@ -91,7 +91,7 @@ protected virtual ICollection Validate(JToken token, JsonSchema return errors; } - private void ValidateType(JToken token, JsonSchema schema, SchemaType schemaType, string propertyName, string propertyPath, List errors) + private void ValidateType(JToken token, JsonSchema schema, SchemaType schemaType, string? propertyName, string propertyPath, List errors) { if (token.Type == JTokenType.Null && schema.IsNullable(schemaType)) { @@ -142,7 +142,7 @@ private IEnumerable GetTypes(JsonSchema schema) return JsonObjectTypes.Where(t => schema.Type.HasFlag(t)); } - private void ValidateAnyOf(JToken token, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateAnyOf(JToken token, JsonSchema schema, string? propertyName, string propertyPath, List errors) { if (schema._anyOf.Count > 0) { @@ -154,7 +154,7 @@ private void ValidateAnyOf(JToken token, JsonSchema schema, string propertyName, } } - private void ValidateAllOf(JToken token, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateAllOf(JToken token, JsonSchema schema, string? propertyName, string propertyPath, List errors) { if (schema._allOf.Count > 0) { @@ -166,7 +166,7 @@ private void ValidateAllOf(JToken token, JsonSchema schema, string propertyName, } } - private void ValidateOneOf(JToken token, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateOneOf(JToken token, JsonSchema schema, string? propertyName, string? propertyPath, List errors) { if (schema._oneOf.Count > 0) { @@ -178,7 +178,7 @@ private void ValidateOneOf(JToken token, JsonSchema schema, string propertyName, } } - private void ValidateNot(JToken token, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateNot(JToken token, JsonSchema schema, string? propertyName, string? propertyPath, List errors) { if (schema.Not != null && Validate(token, schema.Not).Count == 0) { @@ -186,7 +186,7 @@ private void ValidateNot(JToken token, JsonSchema schema, string propertyName, s } } - private void ValidateNull(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateNull(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (type.IsNull() && token != null && token.Type != JTokenType.Null) { @@ -194,7 +194,7 @@ private void ValidateNull(JToken token, JsonSchema schema, JsonObjectType type, } } - private void ValidateEnum(JToken token, JsonSchema schema, SchemaType schemaType, string propertyName, string propertyPath, List errors) + private void ValidateEnum(JToken token, JsonSchema schema, SchemaType schemaType, string? propertyName, string propertyPath, List errors) { if (schema.IsNullable(schemaType) && token?.Type == JTokenType.Null) { @@ -207,7 +207,7 @@ private void ValidateEnum(JToken token, JsonSchema schema, SchemaType schemaType } } - private void ValidateString(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateString(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { var isString = token.Type == JTokenType.String || token.Type == JTokenType.Date || token.Type == JTokenType.Guid || token.Type == JTokenType.TimeSpan || @@ -215,7 +215,7 @@ private void ValidateString(JToken token, JsonSchema schema, JsonObjectType type if (isString) { - var value = token.Type == JTokenType.Date ? (token as JValue).ToString("yyyy-MM-ddTHH:mm:ssK") : token.Value(); + var value = token.Type == JTokenType.Date && token is JValue jValue ? jValue.ToString("yyyy-MM-ddTHH:mm:ssK") : token.Value(); if (value != null) { if (!string.IsNullOrEmpty(schema.Pattern)) @@ -236,7 +236,7 @@ private void ValidateString(JToken token, JsonSchema schema, JsonObjectType type } if (!string.IsNullOrEmpty(schema.Format) - && _formatValidatorsMap.TryGetValue(schema.Format, out var formatValidators) + && _formatValidatorsMap.TryGetValue(schema.Format!, out var formatValidators) && !formatValidators.Any(x => x.IsValid(value, token.Type))) { errors.AddRange(formatValidators.Select(x => x.ValidationErrorKind).Distinct() @@ -250,7 +250,7 @@ private void ValidateString(JToken token, JsonSchema schema, JsonObjectType type } } - private void ValidateNumber(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateNumber(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (type.IsNumber() && token.Type != JTokenType.Float && token.Type != JTokenType.Integer) { @@ -320,7 +320,7 @@ private void ValidateNumber(JToken token, JsonSchema schema, JsonObjectType type } } - private void ValidateInteger(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateInteger(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (type.IsInteger() && token.Type != JTokenType.Integer) { @@ -328,7 +328,7 @@ private void ValidateInteger(JToken token, JsonSchema schema, JsonObjectType typ } } - private void ValidateBoolean(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateBoolean(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (type.IsBoolean() && token.Type != JTokenType.Boolean) { @@ -336,7 +336,7 @@ private void ValidateBoolean(JToken token, JsonSchema schema, JsonObjectType typ } } - private void ValidateObject(JToken token, JsonSchema schema, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateObject(JToken token, JsonSchema schema, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (type.IsObject() && !(token is JObject)) { @@ -344,7 +344,7 @@ private void ValidateObject(JToken token, JsonSchema schema, JsonObjectType type } } - private void ValidateProperties(JToken token, JsonSchema schema, SchemaType schemaType, string propertyName, string propertyPath, List errors) + private void ValidateProperties(JToken token, JsonSchema schema, SchemaType schemaType, string? propertyName, string propertyPath, List errors) { var obj = token as JObject; if (obj == null && schema.Type.IsNull()) @@ -360,7 +360,9 @@ private void ValidateProperties(JToken token, JsonSchema schema, SchemaType sche { var newPropertyPath = GetPropertyPath(propertyPath, propertyInfo.Key); - if (obj != null && TryGetPropertyWithStringComparer(obj, propertyInfo.Key, stringComparer, out var value)) + if (obj != null && + TryGetPropertyWithStringComparer(obj, propertyInfo.Key, stringComparer, out var value) && + value != null) { if (value.Type == JTokenType.Null && propertyInfo.Value.IsNullable(schemaType)) { @@ -411,7 +413,7 @@ private string GetPropertyPath(string propertyPath, string propertyName) return !string.IsNullOrEmpty(propertyPath) ? propertyPath + "." + propertyName : propertyName; } - private void ValidateMaxProperties(JToken token, IList properties, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateMaxProperties(JToken token, IList properties, JsonSchema schema, string? propertyName, string propertyPath, List errors) { if (schema.MaxProperties > 0 && properties.Count() > schema.MaxProperties) { @@ -419,7 +421,7 @@ private void ValidateMaxProperties(JToken token, IList properties, Js } } - private void ValidateMinProperties(JToken token, IList properties, JsonSchema schema, string propertyName, string propertyPath, List errors) + private void ValidateMinProperties(JToken token, IList properties, JsonSchema schema, string? propertyName, string propertyPath, List errors) { if (schema.MinProperties > 0 && properties.Count() < schema.MinProperties) { @@ -450,7 +452,7 @@ private void ValidatePatternProperties(List additionalProperties, Jso } private void ValidateAdditionalProperties(JToken token, List additionalProperties, JsonSchema schema, SchemaType schemaType, - string propertyName, string propertyPath, List errors) + string? propertyName, string propertyPath, List errors) { if (schema.AdditionalPropertiesSchema != null) { @@ -476,7 +478,7 @@ private void ValidateAdditionalProperties(JToken token, List addition } } - private void ValidateArray(JToken token, JsonSchema schema, SchemaType schemaType, JsonObjectType type, string propertyName, string propertyPath, List errors) + private void ValidateArray(JToken token, JsonSchema schema, SchemaType schemaType, JsonObjectType type, string? propertyName, string propertyPath, List errors) { if (token is JArray array) { @@ -520,7 +522,7 @@ private void ValidateArray(JToken token, JsonSchema schema, SchemaType schemaTyp } } - private void ValidateAdditionalItems(JToken item, JsonSchema schema, SchemaType schemaType, int index, string propertyPath, List errors) + private void ValidateAdditionalItems(JToken item, JsonSchema schema, SchemaType schemaType, int index, string? propertyPath, List errors) { if (schema.Items.Count > 0) { @@ -555,7 +557,7 @@ private void ValidateAdditionalItems(JToken item, JsonSchema schema, SchemaType } } - private ChildSchemaValidationError TryCreateChildSchemaError(JToken token, JsonSchema schema, SchemaType schemaType, ValidationErrorKind errorKind, string property, string path) + private ChildSchemaValidationError? TryCreateChildSchemaError(JToken token, JsonSchema schema, SchemaType schemaType, ValidationErrorKind errorKind, string property, string path) { var errors = Validate(token, schema.ActualSchema, schemaType, null, path); if (errors.Count == 0) @@ -569,7 +571,7 @@ private ChildSchemaValidationError TryCreateChildSchemaError(JToken token, JsonS return new ChildSchemaValidationError(errorKind, property, path, errorDictionary, token, schema); } - private bool TryGetPropertyWithStringComparer(JObject obj, string propertyName, StringComparer comparer, out JToken value) + private bool TryGetPropertyWithStringComparer(JObject obj, string propertyName, StringComparer comparer, out JToken? value) { // This method mimics the behavior of the JObject.TryGetValue(string property, StringComparison comparison, out JToken) // extension method using a StringComparer class instead of StringComparison enum value. diff --git a/src/NJsonSchema/Validation/JsonSchemaValidatorOptions.cs b/src/NJsonSchema/Validation/JsonSchemaValidatorOptions.cs index 8b8e4535d..361e91a1e 100644 --- a/src/NJsonSchema/Validation/JsonSchemaValidatorOptions.cs +++ b/src/NJsonSchema/Validation/JsonSchemaValidatorOptions.cs @@ -8,14 +8,8 @@ namespace NJsonSchema.Validation /// Class to configure the behavior of . public class JsonSchemaValidatorSettings { - private StringComparer _propertyStringComparer; - /// Gets or sets the used to compare object properties. - public StringComparer PropertyStringComparer - { - get => _propertyStringComparer ?? StringComparer.Ordinal; - set => _propertyStringComparer = value; - } + public StringComparer PropertyStringComparer { get; set; } = StringComparer.Ordinal; /// Gets or sets the format validators. public IEnumerable FormatValidators { get; set; } = new IFormatValidator[] diff --git a/src/NJsonSchema/Validation/MultiTypeValidationError.cs b/src/NJsonSchema/Validation/MultiTypeValidationError.cs index 846078800..d5d6af8d5 100644 --- a/src/NJsonSchema/Validation/MultiTypeValidationError.cs +++ b/src/NJsonSchema/Validation/MultiTypeValidationError.cs @@ -21,7 +21,7 @@ public class MultiTypeValidationError : ValidationError /// The error list. /// The token that failed to validate. /// The schema that contains the validation rule. - public MultiTypeValidationError(ValidationErrorKind kind, string property, string path, IReadOnlyDictionary> errors, JToken token, JsonSchema schema) + public MultiTypeValidationError(ValidationErrorKind kind, string? property, string path, IReadOnlyDictionary> errors, JToken token, JsonSchema schema) : base(kind, property, path, token, schema) { diff --git a/src/NJsonSchema/Validation/ValidationError.cs b/src/NJsonSchema/Validation/ValidationError.cs index e620fed6a..c13783b7b 100644 --- a/src/NJsonSchema/Validation/ValidationError.cs +++ b/src/NJsonSchema/Validation/ValidationError.cs @@ -20,7 +20,7 @@ public class ValidationError /// The property path. /// The token that failed to validate. /// The schema that contains the validation rule. - public ValidationError(ValidationErrorKind errorKind, string propertyName, string propertyPath, JToken token, JsonSchema schema) + public ValidationError(ValidationErrorKind errorKind, string? propertyName, string? propertyPath, JToken? token, JsonSchema schema) { Kind = errorKind; Property = propertyName; @@ -30,7 +30,7 @@ public ValidationError(ValidationErrorKind errorKind, string propertyName, strin HasLineInfo = lineInfo != null && lineInfo.HasLineInfo(); if (HasLineInfo) { - LineNumber = lineInfo.LineNumber; + LineNumber = lineInfo!.LineNumber; LinePosition = lineInfo.LinePosition; } else @@ -46,10 +46,10 @@ public ValidationError(ValidationErrorKind errorKind, string propertyName, strin public ValidationErrorKind Kind { get; private set; } /// Gets the property name. - public string Property { get; private set; } + public string? Property { get; private set; } /// Gets the property path. - public string Path { get; private set; } + public string? Path { get; private set; } /// Indicates whether or not the error contains line information. public bool HasLineInfo { get; private set; } diff --git a/src/NJsonSchema/Visitors/AsyncJsonReferenceVisitorBase.cs b/src/NJsonSchema/Visitors/AsyncJsonReferenceVisitorBase.cs index bb5e8a2af..6073785bc 100644 --- a/src/NJsonSchema/Visitors/AsyncJsonReferenceVisitorBase.cs +++ b/src/NJsonSchema/Visitors/AsyncJsonReferenceVisitorBase.cs @@ -39,15 +39,6 @@ protected AsyncJsonReferenceVisitorBase(IContractResolver contractResolver) _contractResolver = contractResolver; } - /// Processes an object. - /// The object to process. - /// The task. - [Obsolete("VisitAsync is deprecated, please use VisitAsync with cancellation token insteaed.")] - public virtual async Task VisitAsync(object obj) - { - await VisitAsync(obj, "#", null, new HashSet(), o => throw new NotSupportedException("Cannot replace the root."), CancellationToken.None).ConfigureAwait(false); - } - /// Processes an object. /// The object to process. /// Cancellation token instance @@ -63,7 +54,7 @@ public virtual async Task VisitAsync(object obj, CancellationToken cancellationT /// The type name hint. /// The cancellation token /// The task. - protected abstract Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint, CancellationToken cancellationToken); + protected abstract Task VisitJsonReferenceAsync(IJsonReference reference, string path, string? typeNameHint, CancellationToken cancellationToken); /// Processes an object. /// The object to process. @@ -73,7 +64,7 @@ public virtual async Task VisitAsync(object obj, CancellationToken cancellationT /// The replacer. /// The cancellation token /// The task. - protected virtual async Task VisitAsync(object obj, string path, string typeNameHint, ISet checkedObjects, Action replacer, CancellationToken cancellationToken) + protected virtual async Task VisitAsync(object obj, string path, string? typeNameHint, ISet checkedObjects, Action replacer, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (obj == null || checkedObjects.Contains(obj)) @@ -193,15 +184,15 @@ await VisitAsync(p.Value, path + "/definitions/" + p.Key, p.Key, checkedObjects, { foreach (var property in contract.Properties.Where(p => { - bool isJsonSchemaProperty = obj is JsonSchema && JsonSchema.JsonSchemaPropertiesCache.Contains(p.UnderlyingName); + bool isJsonSchemaProperty = obj is JsonSchema && p.UnderlyingName != null && JsonSchema.JsonSchemaPropertiesCache.Contains(p.UnderlyingName); return !isJsonSchemaProperty && !p.Ignored && p.ShouldSerialize?.Invoke(obj) != false; })) { - var value = property.ValueProvider.GetValue(obj); + var value = property.ValueProvider?.GetValue(obj); if (value != null) { - await VisitAsync(value, path + "/" + property.PropertyName, property.PropertyName, checkedObjects, o => property.ValueProvider.SetValue(obj, o), cancellationToken).ConfigureAwait(false); + await VisitAsync(value, path + "/" + property.PropertyName, property.PropertyName, checkedObjects, o => property.ValueProvider?.SetValue(obj, o), cancellationToken).ConfigureAwait(false); } } } @@ -209,17 +200,21 @@ await VisitAsync(p.Value, path + "/definitions/" + p.Key, p.Key, checkedObjects, { foreach (var key in dictionary.Keys.OfType().ToArray()) { - await VisitAsync(dictionary[key], path + "/" + key, key.ToString(), checkedObjects, o => + var value = dictionary[key]; + if (value != null) { - if (o != null) - { - dictionary[key] = (JsonSchema)o; - } - else + await VisitAsync(value, path + "/" + key, key.ToString(), checkedObjects, o => { - dictionary.Remove(key); - } - }, cancellationToken).ConfigureAwait(false); + if (o != null) + { + dictionary[key] = (JsonSchema)o; + } + else + { + dictionary.Remove(key); + } + }, cancellationToken).ConfigureAwait(false); + } } // Custom dictionary type with additional properties (OpenApiPathItem) diff --git a/src/NJsonSchema/Visitors/AsyncJsonSchemaVisitorBase.cs b/src/NJsonSchema/Visitors/AsyncJsonSchemaVisitorBase.cs index 0e6cf8d1d..33e23a8ef 100644 --- a/src/NJsonSchema/Visitors/AsyncJsonSchemaVisitorBase.cs +++ b/src/NJsonSchema/Visitors/AsyncJsonSchemaVisitorBase.cs @@ -21,7 +21,7 @@ public abstract class AsyncJsonSchemaVisitorBase : AsyncJsonReferenceVisitorBase /// The type name hint. /// The cancellation token /// The task. - protected abstract Task VisitSchemaAsync(JsonSchema schema, string path, string typeNameHint, CancellationToken cancellationToken); + protected abstract Task VisitSchemaAsync(JsonSchema schema, string path, string? typeNameHint, CancellationToken cancellationToken); /// Called when a is visited. /// The visited schema. @@ -29,7 +29,7 @@ public abstract class AsyncJsonSchemaVisitorBase : AsyncJsonReferenceVisitorBase /// The type name hint. /// The cancellation token /// The task. - protected override async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint, CancellationToken cancellationToken) + protected override async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string? typeNameHint, CancellationToken cancellationToken) { if (reference is JsonSchema schema) { diff --git a/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs b/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs index 0d38bc583..8eaca0277 100644 --- a/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs +++ b/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs @@ -50,7 +50,7 @@ public virtual void Visit(object obj) /// The path. /// The type name hint. /// The task. - protected abstract IJsonReference VisitJsonReference(IJsonReference reference, string path, string typeNameHint); + protected abstract IJsonReference VisitJsonReference(IJsonReference reference, string path, string? typeNameHint); /// Processes an object. /// The object to process. @@ -59,7 +59,7 @@ public virtual void Visit(object obj) /// The checked objects. /// The replacer. /// The task. - protected virtual void Visit(object obj, string path, string typeNameHint, ISet checkedObjects, Action replacer) + protected virtual void Visit(object obj, string path, string? typeNameHint, ISet checkedObjects, Action replacer) { if (obj == null || !checkedObjects.Add(obj)) { @@ -173,15 +173,19 @@ protected virtual void Visit(object obj, string path, string typeNameHint, ISet< { foreach (var property in contract.Properties.Where(p => { - bool isJsonSchemaProperty = obj is JsonSchema && JsonSchema.JsonSchemaPropertiesCache.Contains(p.UnderlyingName); + var isJsonSchemaProperty = + obj is JsonSchema && + p.UnderlyingName != null && + JsonSchema.JsonSchemaPropertiesCache.Contains(p.UnderlyingName); + return !isJsonSchemaProperty && !p.Ignored && p.ShouldSerialize?.Invoke(obj) != false; })) { - var value = property.ValueProvider.GetValue(obj); + var value = property.ValueProvider?.GetValue(obj); if (value != null) { - Visit(value, path + "/" + property.PropertyName, property.PropertyName, checkedObjects, o => property.ValueProvider.SetValue(obj, o)); + Visit(value, path + "/" + property.PropertyName, property.PropertyName!, checkedObjects, o => property.ValueProvider?.SetValue(obj, o)); } } } @@ -189,17 +193,21 @@ protected virtual void Visit(object obj, string path, string typeNameHint, ISet< { foreach (var key in dictionary.Keys.OfType().ToArray()) { - Visit(dictionary[key], path + "/" + key, key.ToString(), checkedObjects, o => + var value = dictionary[key]; + if (value != null) { - if (o != null) - { - dictionary[key] = (JsonSchema)o; - } - else + Visit(value, path + "/" + key, key.ToString(), checkedObjects, o => { - dictionary.Remove(key); - } - }); + if (o != null) + { + dictionary[key] = (JsonSchema)o; + } + else + { + dictionary.Remove(key); + } + }); + } } // Custom dictionary type with additional properties (OpenApiPathItem) diff --git a/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs b/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs index 563a422d0..2e8c58d91 100644 --- a/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs +++ b/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs @@ -18,14 +18,14 @@ public abstract class JsonSchemaVisitorBase : JsonReferenceVisitorBase /// The path. /// The type name hint. /// The task. - protected abstract JsonSchema VisitSchema(JsonSchema schema, string path, string typeNameHint); + protected abstract JsonSchema VisitSchema(JsonSchema schema, string path, string? typeNameHint); /// Called when a is visited. /// The visited schema. /// The path. /// The type name hint. /// The task. - protected override IJsonReference VisitJsonReference(IJsonReference reference, string path, string typeNameHint) + protected override IJsonReference VisitJsonReference(IJsonReference reference, string path, string? typeNameHint) { if (reference is JsonSchema schema) {