diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/NullableReferenceTypesTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/NullableReferenceTypesTests.cs new file mode 100644 index 000000000..5291206cf --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/NullableReferenceTypesTests.cs @@ -0,0 +1,152 @@ +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using NJsonSchema.CodeGeneration.CSharp; +using NJsonSchema.Generation; +using Xunit; + +namespace NJsonSchema.CodeGeneration.Tests.CSharp +{ + public class NullableReferenceTypesTests + { + private class ClassWithRequiredObject + { + public object Property { get; set; } + + [Required] + [Newtonsoft.Json.JsonProperty("property2", Required = Newtonsoft.Json.Required.Always)] + public object Property2 { get; set; } + } + + [Fact] + public async Task When_property_is_optional_and_GenerateNullableReferenceTypes_is_not_set_then_CSharp_property_is_not_nullable() + { + //// Arrange + var schema = JsonSchema.FromType(new JsonSchemaGeneratorSettings + { + SchemaType = SchemaType.OpenApi3 + }); + var schemaData = schema.ToJson(); + + //// Act + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + ClassStyle = CSharpClassStyle.Poco, + SchemaType = SchemaType.OpenApi3, + GenerateNullableReferenceTypes = false + }); + var code = generator.GenerateFile("MyClass"); + + //// Assert + Assert.Contains("public object Property { get; set; }", code); + Assert.Contains("public object Property2 { get; set; }", code); + } + + [Fact] + public async Task When_property_is_optional_and_GenerateNullableOptionalProperties_is_set_then_CSharp_property_is_nullable() + { + //// Arrange + var schema = JsonSchema.FromType(new JsonSchemaGeneratorSettings + { + SchemaType = SchemaType.OpenApi3 + }); + var schemaData = schema.ToJson(); + + //// Act + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + ClassStyle = CSharpClassStyle.Poco, + SchemaType = SchemaType.OpenApi3, + GenerateNullableReferenceTypes = true + }); + var code = generator.GenerateFile("MyClass"); + + //// Assert + Assert.Contains("public object? Property { get; set; }= default!;", code); + Assert.Contains("public object Property2 { get; set; }= default!;", code); + } + + [Fact] + public async Task When_generating_from_json_schema_property_is_optional_and_GenerateNullableOptionalProperties_is_not_set_then_CSharp_property() + { + //// Arrange + + // CSharpGenerator `new object()` adds = new object() initializer to property only if it's explicitly marked + // as having `type: object` in json schema + var schemaJson = @" + { + ""type"": ""object"", + ""required"": [ + ""property2"" + ], + ""properties"": { + ""Property"": { + ""x-nullable"": true, + ""type"": ""object"" + }, + ""property2"": { + ""type"": ""object"" + } + } + } + "; + + var schema = await JsonSchema.FromJsonAsync(schemaJson); + var schemaData = schema.ToJson(); + + //// Act + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + ClassStyle = CSharpClassStyle.Poco, + SchemaType = SchemaType.OpenApi3, + GenerateNullableReferenceTypes = false + }); + var code = generator.GenerateFile("MyClass"); + + //// Assert + Assert.Contains("public object Property { get; set; }", code); + Assert.Contains("public object Property2 { get; set; } = new object();", code); + } + + [Fact] + public async Task When_generating_from_json_schema_property_is_optional_and_GenerateNullableOptionalProperties_is_set_then_CSharp_property() + { + //// Arrange + + // CSharpGenerator `new object()` adds = new object() initializer to property only if it's explicitly marked + // as having `type: object` in json schema + var schemaJson = @" + { + ""type"": ""object"", + ""required"": [ + ""property2"" + ], + ""properties"": { + ""Property"": { + ""x-nullable"": true, + ""type"": ""object"" + }, + ""property2"": { + ""type"": ""object"" + } + } + } + "; + + var schema = await JsonSchema.FromJsonAsync(schemaJson); + var schemaData = schema.ToJson(); + + //// Act + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + ClassStyle = CSharpClassStyle.Poco, + SchemaType = SchemaType.OpenApi3, + GenerateNullableReferenceTypes = true + }); + var code = generator.GenerateFile("MyClass"); + + //// Assert + Assert.Contains("public object? Property { get; set; }= default!;", code); + Assert.Contains("public object Property2 { get; set; } = new object();", code); + } + } +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs index cf0a5eef3..fb26820d8 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs @@ -75,13 +75,15 @@ schema is JsonSchemaProperty property && isNullable = true; } + var markAsNullableType = Settings.GenerateNullableReferenceTypes && isNullable; + if (schema.ActualTypeSchema.IsAnyType && schema.InheritedSchema == null && // not in inheritance hierarchy schema.AllOf.Count == 0 && !Types.Keys.Contains(schema) && !schema.HasReference) { - return Settings.AnyType; + return markAsNullableType ? Settings.AnyType + "?" : Settings.AnyType; } var type = schema.ActualTypeSchema.Type; @@ -107,7 +109,8 @@ schema is JsonSchemaProperty property && return ResolveBoolean(isNullable); } - var nullableReferenceType = Settings.GenerateNullableReferenceTypes && isNullable ? "?" : string.Empty; + + var nullableReferenceType = markAsNullableType ? "?" : string.Empty; if (schema.IsBinary) { diff --git a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj index af7c4fedc..2d762a185 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj +++ b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj @@ -2,7 +2,7 @@ netstandard1.3;netstandard2.0;net451 JSON Schema reader, generator and validator for .NET - 10.3.1 + 10.3.3 json schema validation generator .net Copyright © Rico Suter, 2020 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj index c3783337e..06d707c59 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj +++ b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj @@ -2,7 +2,7 @@ netstandard1.3;netstandard2.0;net451 JSON Schema reader, generator and validator for .NET - 10.3.1 + 10.3.3 json schema validation generator .net Copyright © Rico Suter, 2020 https://github.com/RicoSuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Class.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Class.liquid index 6ba1cf28e..46f37bd93 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Class.liquid +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Class.liquid @@ -93,7 +93,7 @@ {% endif -%} } - static fromJS(data: any{% if HandleReferences %}, _mappings?: any{% endif %}): {{ ClassName }} { + static fromJS(data: any{% if HandleReferences %}, _mappings?: any{% endif %}): {{ ClassName }}{% if HandleReferences %} | null{% endif %} { data = typeof data === 'object' ? data : {}; {% if HandleReferences -%} {% if HasBaseDiscriminator -%} diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/File.ReferenceHandling.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/File.ReferenceHandling.liquid index 10d8401a7..092651124 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/File.ReferenceHandling.liquid +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/File.ReferenceHandling.liquid @@ -41,7 +41,7 @@ return json; } -function createInstance(data: any, mappings: any, type: any): T { +function createInstance(data: any, mappings: any, type: any): T | null { if (!mappings) mappings = []; if (!data) diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/KnockoutClass.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/KnockoutClass.liquid index 360966182..8a108c6b0 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/KnockoutClass.liquid +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/KnockoutClass.liquid @@ -37,7 +37,7 @@ } } - static fromJS(data: any{% if HandleReferences %}, _mappings?: any{% endif %}): {{ ClassName }} { + static fromJS(data: any{% if HandleReferences %}, _mappings?: any{% endif %}): {{ ClassName }}{% if HandleReferences %} | null{% endif %} { {% if HandleReferences -%} {% if HasBaseDiscriminator -%} {% for derivedClass in DerivedClasses -%} diff --git a/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs index d3b6a3b32..858e9d241 100644 --- a/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs +++ b/src/NJsonSchema.CodeGeneration/Models/PropertyModelBase.cs @@ -70,6 +70,9 @@ protected PropertyModelBase( /// Gets the property extension data. public IDictionary ExtensionData => _property.ExtensionData; + /// Gets the JSON Schema format property. + public string Format => _property.ActualSchema.Format; + /// Gets the type name hint for the property. protected string GetTypeNameHint() { diff --git a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj index bf683063d..703e17552 100644 --- a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj +++ b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj @@ -2,7 +2,7 @@ netstandard1.3;netstandard2.0;net451 JSON Schema reader, generator and validator for .NET - 10.3.1 + 10.3.3 json schema validation generator .net Copyright © Rico Suter, 2020 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema.Tests/Generation/SampleJsonDataGeneratorTests.cs b/src/NJsonSchema.Tests/Generation/SampleJsonDataGeneratorTests.cs index f4dbd0741..5d6700591 100644 --- a/src/NJsonSchema.Tests/Generation/SampleJsonDataGeneratorTests.cs +++ b/src/NJsonSchema.Tests/Generation/SampleJsonDataGeneratorTests.cs @@ -141,7 +141,7 @@ public async Task PropertyWithIntegerMinimumDefiniton() [Fact] - public async Task PropertyWithFloatMinimumDefiniton() + public async Task PropertyWithFloatMinimumDefinition() { //// Arrange var data = @"{ @@ -172,8 +172,8 @@ public async Task PropertyWithFloatMinimumDefiniton() ""properties"": { ""value"": { ""type"": ""number"", - ""maximum"": 5.0, - ""minimum"": 1.0 + ""maximum"": 5.00001, + ""minimum"": 1.000012 } } } @@ -188,7 +188,7 @@ public async Task PropertyWithFloatMinimumDefiniton() var validationResult = schema.Validate(testJson); Assert.NotNull(validationResult); Assert.Equal(0, validationResult.Count); - Assert.Equal(1.0, testJson.SelectToken("body.numberContent.value").Value()); + Assert.Equal(1.000012, testJson.SelectToken("body.numberContent.value").Value()); } [Fact] diff --git a/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj b/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj index 76cc1d586..9a398640a 100644 --- a/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj +++ b/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj @@ -2,7 +2,7 @@ netstandard1.3;netstandard2.0;net45 JSON Schema reader, generator and validator for .NET - 10.3.1 + 10.3.3 json schema validation generator .net Copyright © Rico Suter, 2020 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs b/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs index 33e1ac26f..a4dcb7eba 100644 --- a/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs +++ b/src/NJsonSchema/Generation/SampleJsonDataGenerator.cs @@ -102,15 +102,15 @@ private static JToken HandleNumberType(JsonSchema schema) { if (schema.ExclusiveMinimumRaw != null) { - return JToken.FromObject(float.Parse(schema.Minimum.ToString()) + 0.1); + return JToken.FromObject((decimal)(float.Parse(schema.Minimum.ToString()) + 0.1)); } else if (schema.ExclusiveMinimum != null) { - return JToken.FromObject(float.Parse(schema.ExclusiveMinimum.ToString())); + return JToken.FromObject(decimal.Parse(schema.ExclusiveMinimum.ToString())); } else if (schema.Minimum.HasValue) { - return float.Parse(schema.Minimum.ToString()); + return decimal.Parse(schema.Minimum.ToString()); } return JToken.FromObject(0.0); } diff --git a/src/NJsonSchema/NJsonSchema.csproj b/src/NJsonSchema/NJsonSchema.csproj index 541124a00..3ac5ecda0 100644 --- a/src/NJsonSchema/NJsonSchema.csproj +++ b/src/NJsonSchema/NJsonSchema.csproj @@ -2,7 +2,7 @@ netstandard1.0;netstandard2.0;net40;net45 JSON Schema reader, generator and validator for .NET - 10.3.1 + 10.3.3 json schema validation generator .net Copyright © Rico Suter, 2020 https://github.com/RicoSuter/NJsonSchema/blob/master/LICENSE.md @@ -28,7 +28,7 @@ - +