diff --git a/src/Json.Schema.ToDotNet.UnitTests/Hints/InterfaceHintTests.cs b/src/Json.Schema.ToDotNet.UnitTests/Hints/InterfaceHintTests.cs index c135cc4..3487f0a 100644 --- a/src/Json.Schema.ToDotNet.UnitTests/Hints/InterfaceHintTests.cs +++ b/src/Json.Schema.ToDotNet.UnitTests/Hints/InterfaceHintTests.cs @@ -42,7 +42,7 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests ], ""C.Value2"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ""internal"" diff --git a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyModifiersHintTests.cs b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintModifiersTests.cs similarity index 90% rename from src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyModifiersHintTests.cs rename to src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintModifiersTests.cs index be2df72..701db19 100644 --- a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyModifiersHintTests.cs +++ b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintModifiersTests.cs @@ -5,7 +5,7 @@ using Xunit; namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests { - public class PropertyModifiersHintTests : HintTestBase + public class PropertyHintModifiersTests : HintTestBase { public static readonly TheoryData TestCases = new TheoryData { @@ -23,7 +23,7 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests @"{ ""C.TheProperty"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ] @@ -62,7 +62,7 @@ namespace N @"{ ""C.TheProperty"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ""internal"" @@ -102,7 +102,7 @@ namespace N @"{ ""C.TheProperty"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ""internal"", @@ -143,7 +143,7 @@ namespace N @"{ ""C.TheProperty"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ""invalid_modifier"" @@ -172,7 +172,7 @@ namespace N @"{ ""*.TheProperty"": [ { - ""kind"": ""PropertyModifiersHint"", + ""kind"": ""PropertyHint"", ""arguments"": { ""modifiers"": [ ""internal"", @@ -200,9 +200,9 @@ namespace N ), }; - [Theory(DisplayName = nameof(PropertyModifiersHint))] + [Theory(DisplayName = nameof(PropertyHintModifiersTest))] [MemberData(nameof(TestCases))] - public void PropertyModifiersHint(HintTestCase testCase) + public void PropertyHintModifiersTest(HintTestCase testCase) { RunHintTestCase(testCase); } diff --git a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyNameHintTests.cs b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintNameTests.cs similarity index 53% rename from src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyNameHintTests.cs rename to src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintNameTests.cs index f8558f0..7df81b1 100644 --- a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyNameHintTests.cs +++ b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintNameTests.cs @@ -5,7 +5,7 @@ using Xunit; namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests { - public class PropertyNameHintTests : HintTestBase + public class PropertyHintNameTests : HintTestBase { public static readonly TheoryData TestCases = new TheoryData { @@ -24,9 +24,9 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests @"{ ""C.$schema"": [ { - ""kind"": ""PropertyNameHint"", + ""kind"": ""PropertyHint"", ""arguments"": { - ""dotNetPropertyName"": ""SchemaUri"" + ""name"": ""SchemaUri"" } } ] @@ -45,51 +45,13 @@ namespace N [DataMember(Name = ""$schema"", IsRequired = false, EmitDefaultValue = false)] public Uri SchemaUri { get; set; } } -}" - ), - - new HintTestCase( - "Specifies integer property name", -@"{ - ""type"": ""object"", - ""properties"": { - ""itemCount"": { - ""type"": ""integer"" - } - } -}", - -@"{ - ""C.ItemCount"": [ - { - ""kind"": ""PropertyNameHint"", - ""arguments"": { - ""dotNetPropertyName"": ""RenamedItemCount"" - } - } - ] -}", - -@"using System; -using System.CodeDom.Compiler; -using System.Runtime.Serialization; - -namespace N -{ - [DataContract] - [GeneratedCode(""Microsoft.Json.Schema.ToDotNet"", """ + VersionConstants.FileVersion + @""")] - public partial class C - { - [DataMember(Name = ""itemCount"", IsRequired = false, EmitDefaultValue = false)] - public int? RenamedItemCount { get; set; } - } }" ) }; - [Theory(DisplayName = nameof(PropertyNameHint))] + [Theory(DisplayName = nameof(PropertyHintNameTest))] [MemberData(nameof(TestCases))] - public void PropertyNameHint(HintTestCase testCase) + public void PropertyHintNameTest(HintTestCase testCase) { RunHintTestCase(testCase); } diff --git a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTests.cs b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTests.cs new file mode 100644 index 0000000..0a413f7 --- /dev/null +++ b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTests.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests +{ + public class PropertyHintTests : HintTestBase + { + public static readonly TheoryData TestCases = new TheoryData + { + new HintTestCase( + "Specifies property name", +@"{ + ""type"": ""object"", + ""properties"": { + ""TheNullableBigIntegerProperty"": { + ""type"": ""integer"" + }, + } +}", + +@"{ + ""C.TheNullableBigIntegerProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""modifiers"": [ + ""internal"", + ""override"" + ], + ""typeName"": ""BigInteger"", + ""name"": ""OverrideTheNullableBigIntegerProperty"" + } + } + ] +}", + +@"using System; +using System.CodeDom.Compiler; +using System.Numerics; +using System.Runtime.Serialization; + +namespace N +{ + [DataContract] + [GeneratedCode(""Microsoft.Json.Schema.ToDotNet"", """ + VersionConstants.FileVersion + @""")] + public partial class C + { + [DataMember(Name = ""TheNullableBigIntegerProperty"", IsRequired = false, EmitDefaultValue = false)] + internal override BigInteger? OverrideTheNullableBigIntegerProperty { get; set; } + } +}" + ) + }; + + [Theory(DisplayName = nameof(PropertyHintTest))] + [MemberData(nameof(TestCases))] + public void PropertyHintTest(HintTestCase testCase) + { + RunHintTestCase(testCase); + } + } +} diff --git a/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTypeNameTests.cs b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTypeNameTests.cs new file mode 100644 index 0000000..bf0651e --- /dev/null +++ b/src/Json.Schema.ToDotNet.UnitTests/Hints/PropertyHintTypeNameTests.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.Json.Schema.ToDotNet.Hints.UnitTests +{ + public class PropertyHintTypeNameTests : HintTestBase + { + public static readonly TheoryData TestCases = new TheoryData + { + new HintTestCase( + "Specifies property name", +@"{ + ""type"": ""object"", + ""properties"": { + ""TheNullableBigIntegerProperty"": { + ""type"": ""integer"" + }, + ""TheBigIntegerProperty"": { + ""type"": ""integer"", + ""default"": ""-1"" + }, + ""TheIntegerProperty"": { + ""type"": ""integer"", + ""default"": ""-1"", + }, + ""TheLongProperty"": { + ""type"": ""integer"", + ""default"": ""-1"" + }, + ""TheStringProperty"": { + ""type"": ""integer"", + ""default"": ""-1"" + }, + ""TheNullableGuidProperty"": { + ""type"": ""string"" + }, + ""TheUriProperty"": { + ""type"": ""string"" + }, + ""TheBoolStringProperty"": { + ""type"": ""boolean"" + }, + ""TheStringBoolProperty"": { + ""type"": ""string"" + }, + ""TheDecimalProperty"": { + ""type"": ""number"", + ""default"": ""1.11111"" + }, + ""TheDoubleProperty"": { + ""type"": ""number"", + ""default"": ""1.11111"" + }, + } +}", + +@"{ + ""C.TheNullableBigIntegerProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""BigInteger"" + } + } + ], + ""C.TheLongProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""Long"" + } + } + ], + ""C.TheStringProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""String"" + } + } + ], + ""C.TheNullableGuidProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""Guid"" + } + } + ], + ""C.TheUriProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""Uri"" + } + } + ], + ""C.TheBoolStringProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""String"" + } + } + ], + ""C.TheStringBoolProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""Bool"" + } + } + ], + ""C.TheDecimalProperty"": [ + { + ""kind"": ""PropertyHint"", + ""arguments"": { + ""typeName"": ""Decimal"" + } + } + ] +}", + +@"using System; +using System.CodeDom.Compiler; +using System.ComponentModel; +using System.Numerics; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace N +{ + [DataContract] + [GeneratedCode(""Microsoft.Json.Schema.ToDotNet"", """ + VersionConstants.FileVersion + @""")] + public partial class C + { + [DataMember(Name = ""TheNullableBigIntegerProperty"", IsRequired = false, EmitDefaultValue = false)] + public BigInteger? TheNullableBigIntegerProperty { get; set; } + [DataMember(Name = ""TheBigIntegerProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""-1"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public int TheBigIntegerProperty { get; set; } + [DataMember(Name = ""TheIntegerProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""-1"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public int TheIntegerProperty { get; set; } + [DataMember(Name = ""TheLongProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""-1"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public long TheLongProperty { get; set; } + [DataMember(Name = ""TheStringProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""-1"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public string TheStringProperty { get; set; } + [DataMember(Name = ""TheNullableGuidProperty"", IsRequired = false, EmitDefaultValue = false)] + public Guid? TheNullableGuidProperty { get; set; } + [DataMember(Name = ""TheUriProperty"", IsRequired = false, EmitDefaultValue = false)] + public Uri TheUriProperty { get; set; } + [DataMember(Name = ""TheBoolStringProperty"", IsRequired = false, EmitDefaultValue = false)] + public string TheBoolStringProperty { get; set; } + [DataMember(Name = ""TheStringBoolProperty"", IsRequired = false, EmitDefaultValue = false)] + public bool TheStringBoolProperty { get; set; } + [DataMember(Name = ""TheDecimalProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""1.11111"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public decimal TheDecimalProperty { get; set; } + [DataMember(Name = ""TheDoubleProperty"", IsRequired = false, EmitDefaultValue = false)] + [DefaultValue(""1.11111"")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + public double TheDoubleProperty { get; set; } + } +}" + ) + }; + + [Theory(DisplayName = nameof(PropertyHintTypeNameTest))] + [MemberData(nameof(TestCases))] + public void PropertyHintTypeNameTest(HintTestCase testCase) + { + RunHintTestCase(testCase); + } + } +} diff --git a/src/Json.Schema.ToDotNet/ClassGenerator.cs b/src/Json.Schema.ToDotNet/ClassGenerator.cs index e8c0f55..1210b79 100644 --- a/src/Json.Schema.ToDotNet/ClassGenerator.cs +++ b/src/Json.Schema.ToDotNet/ClassGenerator.cs @@ -425,12 +425,12 @@ namespace Microsoft.Json.Schema.ToDotNet /// protected override SyntaxToken[] GenerateSchemaPropertyModifiers(string propertyName) { - PropertyModifiersHint propertyModifiersHint = HintDictionary?.GetPropertyHint(TypeName, propertyName); + PropertyHint propertyHint = HintDictionary?.GetPropertyHint(TypeName, propertyName); IList modifierTokens; - if (propertyModifiersHint?.Modifiers != null) + if (propertyHint?.Modifiers != null) { - modifierTokens = propertyModifiersHint.Modifiers; + modifierTokens = propertyHint.Modifiers; } else { diff --git a/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs b/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs index 52ab1f6..9cac626 100644 --- a/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs +++ b/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs @@ -109,7 +109,7 @@ namespace Microsoft.Json.Schema.ToDotNet PropertyDeclarationSyntax propDecl = SyntaxFactory.PropertyDeclaration( info.Type, propertyName.ToPascalCase()) - .AddModifiers(GenerateSchemaPropertyModifiers(propertyName)) + .AddModifiers(GenerateSchemaPropertyModifiers(info.SerializedName)) .AddAccessorListAccessors(GeneratePropertyAccessors()); AttributeSyntax[] attributes = GeneratePropertyAttributes(propertyName, info.SerializedName, info.IsRequired, info.DefaultValue, info.Type); diff --git a/src/Json.Schema.ToDotNet/Hints/HintDictionary.cs b/src/Json.Schema.ToDotNet/Hints/HintDictionary.cs index 174ccca..6fa98c6 100644 --- a/src/Json.Schema.ToDotNet/Hints/HintDictionary.cs +++ b/src/Json.Schema.ToDotNet/Hints/HintDictionary.cs @@ -42,8 +42,7 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints [HintKind.DictionaryHint] = CreateDictionaryHint, [HintKind.EnumHint] = CreateEnumHint, [HintKind.InterfaceHint] = CreateInterfaceHint, - [HintKind.PropertyModifiersHint] = CreatePropertyModifiersHint, - [HintKind.PropertyNameHint] = CreatePropertyNameHint + [HintKind.PropertyHint] = CreatePropertyHint }); var infoDictionary = HintInstantiationInfoDictionary.Deserialize(dictionaryText); @@ -193,35 +192,30 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints }; } - private static CodeGenHint CreatePropertyModifiersHint(JObject arguments) + private static CodeGenHint CreatePropertyHint(JObject arguments) { - string[] modifiers = GetArrayArgument(arguments, nameof(PropertyModifiersHint.Modifiers)); + string[] modifiers = GetArrayArgument(arguments, nameof(PropertyHint.Modifiers)); + string typeName = GetArgument(arguments, nameof(PropertyHint.TypeName)); + string name = GetArgument(arguments, nameof(PropertyHint.Name)); - return new PropertyModifiersHint(modifiers); + return new PropertyHint(modifiers, typeName, name); } - private static CodeGenHint CreatePropertyNameHint(JObject arguments) - { - string dotNetPropertyName = GetArgument(arguments, nameof(PropertyNameHint.DotNetPropertyName)); - - return new PropertyNameHint(dotNetPropertyName); - } - - private static T GetArgument(JObject arguments, string dotNetPropertyName) + private static T GetArgument(JObject arguments, string name) { return arguments == null ? default(T) - : arguments.Value(dotNetPropertyName.ToCamelCase()); + : arguments.Value(name.ToCamelCase()); } - private static T[] GetArrayArgument(JObject arguments, string dotNetPropertyName) + private static T[] GetArrayArgument(JObject arguments, string name) { if (arguments == null) { return default(T[]); } - JArray arrayValue = arguments.Value(dotNetPropertyName.ToCamelCase()); + JArray arrayValue = arguments.Value(name.ToCamelCase()); if (arrayValue == null) { return default(T[]); @@ -230,9 +224,9 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints return arrayValue.Values().ToArray(); } - private static IDictionary GetObjectArgument(JObject arguments, string dotNetPropertyName) + private static IDictionary GetObjectArgument(JObject arguments, string name) { - JObject jObject = arguments?.Value(dotNetPropertyName.ToCamelCase()); + JObject jObject = arguments?.Value(name.ToCamelCase()); if (jObject == null) { return null; diff --git a/src/Json.Schema.ToDotNet/Hints/HintKind.cs b/src/Json.Schema.ToDotNet/Hints/HintKind.cs index 0dbbdfa..a7939f4 100644 --- a/src/Json.Schema.ToDotNet/Hints/HintKind.cs +++ b/src/Json.Schema.ToDotNet/Hints/HintKind.cs @@ -24,7 +24,6 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints DictionaryHint, EnumHint, InterfaceHint, - PropertyModifiersHint, - PropertyNameHint + PropertyHint } } diff --git a/src/Json.Schema.ToDotNet/Hints/PropertyModifiersHint.cs b/src/Json.Schema.ToDotNet/Hints/PropertyHint.cs similarity index 69% rename from src/Json.Schema.ToDotNet/Hints/PropertyModifiersHint.cs rename to src/Json.Schema.ToDotNet/Hints/PropertyHint.cs index 8ee7339..76282ae 100644 --- a/src/Json.Schema.ToDotNet/Hints/PropertyModifiersHint.cs +++ b/src/Json.Schema.ToDotNet/Hints/PropertyHint.cs @@ -12,20 +12,27 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints { /// /// Represents a code generation hint that tells the code generator to declare a - /// property with the specified modifiers instead of the default public - /// modifier. + /// property with the specified modifiers, type and name. /// - public class PropertyModifiersHint : CodeGenHint + public class PropertyHint : CodeGenHint { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The property modifiers. /// - public PropertyModifiersHint(IEnumerable modifiers) + /// + /// The type of the .NET property to generate. + /// + /// + /// The name of the .NET property to generate. + /// + public PropertyHint(IEnumerable modifiers, string typeName, string name) { - Modifiers = modifiers.Select(TokenFromModifierName).ToList(); + Modifiers = modifiers?.Select(TokenFromModifierName).ToList(); + TypeName = typeName; + Name = name; } private SyntaxToken TokenFromModifierName(string modifierName) @@ -69,5 +76,15 @@ namespace Microsoft.Json.Schema.ToDotNet.Hints /// Gets the property modifiers. /// public IList Modifiers { get; } + + /// + /// Gets the type of the .NET property to generate. + /// + public string TypeName { get; } + + /// + /// Gets the name of the .NET property to generate. + /// + public string Name { get; } } } diff --git a/src/Json.Schema.ToDotNet/Hints/PropertyNameHint.cs b/src/Json.Schema.ToDotNet/Hints/PropertyNameHint.cs deleted file mode 100644 index 8b6711d..0000000 --- a/src/Json.Schema.ToDotNet/Hints/PropertyNameHint.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Json.Schema.ToDotNet.Hints -{ - /// - /// Represents a code generation hint that tells the code generator to generate a - /// property with the specified name, instead of deriving the .NET property name - /// from the schema property name. - /// - public class PropertyNameHint : CodeGenHint - { - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the .NET property to generate. - /// - public PropertyNameHint(string dotNetPropertyName) - { - if (dotNetPropertyName == null) - { - throw new ArgumentNullException(nameof(dotNetPropertyName)); - } - - DotNetPropertyName = dotNetPropertyName; - } - - /// - /// Gets the name of the .NET property to generate. - /// - public string DotNetPropertyName { get; } - } -} diff --git a/src/Json.Schema.ToDotNet/InterfaceGenerator.cs b/src/Json.Schema.ToDotNet/InterfaceGenerator.cs index c436b23..ff97ea7 100644 --- a/src/Json.Schema.ToDotNet/InterfaceGenerator.cs +++ b/src/Json.Schema.ToDotNet/InterfaceGenerator.cs @@ -73,16 +73,16 @@ namespace Microsoft.Json.Schema.ToDotNet const string WildCard = "*"; string hintDictionaryKey = MakeHintDictionaryKey(propertyName); - PropertyModifiersHint propertyModifiersHint = HintDictionary.GetHint(hintDictionaryKey); - if (propertyModifiersHint == null) + PropertyHint propertyHint = HintDictionary.GetHint(hintDictionaryKey); + if (propertyHint == null) { hintDictionaryKey = WildCard + "." + propertyName.ToPascalCase(); - propertyModifiersHint = HintDictionary.GetHint(hintDictionaryKey); + propertyHint = HintDictionary.GetHint(hintDictionaryKey); } - if (propertyModifiersHint?.Modifiers.Count > 0) + if (propertyHint?.Modifiers.Count > 0) { - bool isPublic = propertyModifiersHint.Modifiers.Contains(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); + bool isPublic = propertyHint.Modifiers.Contains(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); return isPublic; } diff --git a/src/Json.Schema.ToDotNet/PropertyHintTypeName.cs b/src/Json.Schema.ToDotNet/PropertyHintTypeName.cs new file mode 100644 index 0000000..9cc25b9 --- /dev/null +++ b/src/Json.Schema.ToDotNet/PropertyHintTypeName.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.Json.Schema.ToDotNet +{ + /// + /// Supported C# types for . + /// + public enum PropertyHintTypeName + { + Auto, + Int, + Long, + BigInteger, + Double, + Float, + Decimal, + DateTime, + Uri, + Guid, + Bool, + String + } +} diff --git a/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs b/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs index db797bf..5580d58 100644 --- a/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs +++ b/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs @@ -241,28 +241,37 @@ namespace Microsoft.Json.Schema.ToDotNet HashKind scalarValueTypeHashKind = scalarValueTypeNullable ? HashKind.ScalarReferenceType : HashKind.ScalarValueType; - if (propertySchema.IsDateTime()) + var propertyHint = _hintDictionary?.GetHint(_typeName + "." + schemaPropertyName.ToPascalCase()); + + PropertyHintTypeName hintTypeName = PropertyHintTypeName.Auto; + + if (propertyHint?.TypeName != null) + { + Enum.TryParse(propertyHint.TypeName, true, out hintTypeName); + } + + if (hintTypeName == PropertyHintTypeName.DateTime || (hintTypeName == PropertyHintTypeName.Auto && propertySchema.IsDateTime())) { comparisonKind = ComparisonKind.OperatorEquals; hashKind = HashKind.ScalarValueType; initializationKind = InitializationKind.SimpleAssign; type = MakeNamedType("System.DateTime", out namespaceName); } - else if (propertySchema.IsUri()) + else if (hintTypeName == PropertyHintTypeName.Uri || (hintTypeName == PropertyHintTypeName.Auto && propertySchema.IsUri())) { comparisonKind = ComparisonKind.OperatorEquals; hashKind = HashKind.ScalarReferenceType; initializationKind = InitializationKind.Uri; type = MakeNamedType("System.Uri", out namespaceName); } - else if (propertySchema.IsUuid()) + else if (hintTypeName == PropertyHintTypeName.Guid || (hintTypeName == PropertyHintTypeName.Auto && propertySchema.IsUuid())) { comparisonKind = ComparisonKind.OperatorEquals; hashKind = scalarValueTypeHashKind; initializationKind = InitializationKind.SimpleAssign; type = MakeNamedType(GuidType, out namespaceName, scalarValueTypeNullable); } - else if (propertySchema.ShouldBeDictionary(_typeName, schemaPropertyName, _hintDictionary, out DictionaryHint dictionaryHint)) + else if (hintTypeName == PropertyHintTypeName.Auto && propertySchema.ShouldBeDictionary(_typeName, schemaPropertyName, _hintDictionary, out DictionaryHint dictionaryHint)) { comparisonKind = ComparisonKind.Dictionary; hashKind = HashKind.Dictionary; @@ -280,14 +289,14 @@ namespace Microsoft.Json.Schema.ToDotNet type = MakeDictionaryType(entries, schemaPropertyName, dictionaryHint, dictionaryElementSchema); namespaceName = "System.Collections.Generic"; // For IDictionary. } - else if ((referencedEnumTypeName = GetReferencedEnumTypeName(propertySchema)) != null) + else if (hintTypeName == PropertyHintTypeName.Auto && (referencedEnumTypeName = GetReferencedEnumTypeName(propertySchema)) != null) { comparisonKind = ComparisonKind.OperatorEquals; hashKind = HashKind.ScalarValueType; initializationKind = InitializationKind.SimpleAssign; type = MakeNamedType(referencedEnumTypeName, out namespaceName); } - else if (propertySchema.ShouldBeEnum(_typeName, schemaPropertyName, _hintDictionary, out EnumHint enumHint)) + else if (hintTypeName == PropertyHintTypeName.Auto && propertySchema.ShouldBeEnum(_typeName, schemaPropertyName, _hintDictionary, out EnumHint enumHint)) { comparisonKind = ComparisonKind.OperatorEquals; hashKind = HashKind.ScalarValueType; @@ -303,109 +312,116 @@ namespace Microsoft.Json.Schema.ToDotNet { SchemaType propertyType = propertySchema.SafeGetType(); - switch (propertyType) + if (hintTypeName == PropertyHintTypeName.Bool || (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.Boolean)) { - case SchemaType.Boolean: - comparisonKind = ComparisonKind.OperatorEquals; - hashKind = HashKind.ScalarValueType; + comparisonKind = ComparisonKind.OperatorEquals; + hashKind = HashKind.ScalarValueType; + initializationKind = InitializationKind.SimpleAssign; + type = MakePrimitiveType(SchemaType.Boolean); + } + else if ( + hintTypeName == PropertyHintTypeName.Float || + hintTypeName == PropertyHintTypeName.Decimal || + hintTypeName == PropertyHintTypeName.Double || + (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.Number)) + { + comparisonKind = ComparisonKind.OperatorEquals; + hashKind = HashKind.ScalarValueType; + initializationKind = InitializationKind.SimpleAssign; + type = MakeProperNumberType(_generateJsonNumberAs, hintTypeName); + } + else if ( + hintTypeName == PropertyHintTypeName.Int || + hintTypeName == PropertyHintTypeName.Long || + hintTypeName == PropertyHintTypeName.BigInteger || + (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.Integer)) + { + comparisonKind = ComparisonKind.OperatorEquals; + hashKind = scalarValueTypeHashKind; + initializationKind = InitializationKind.SimpleAssign; + type = MakeProperIntegerType( + schemaPropertyName, + _generateJsonIntegerAs, + hintTypeName, + propertySchema.Minimum, propertySchema.ExclusiveMinimum, + propertySchema.Maximum, propertySchema.ExclusiveMaximum, + scalarValueTypeNullable, + out namespaceName); + } + else if (hintTypeName == PropertyHintTypeName.String || (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.String)) + { + comparisonKind = ComparisonKind.OperatorEquals; + hashKind = HashKind.ScalarReferenceType; + initializationKind = InitializationKind.SimpleAssign; + type = MakePrimitiveType(SchemaType.String); + } + else if (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.Object) + { + // If the schema for this property references a named type, + // the generated Init method will initialize it by cloning an object + // of that type. Otherwise, we treat this property as a System.Object + // and just initialize it by assignment. + if (propertySchema.Reference != null) + { + comparisonKind = ComparisonKind.EqualityComparerEquals; + initializationKind = InitializationKind.Clone; + hashKind = HashKind.ObjectModelType; + isOfSchemaDefinedType = true; + } + else + { + comparisonKind = ComparisonKind.ObjectEquals; initializationKind = InitializationKind.SimpleAssign; - type = MakePrimitiveType(propertyType); - break; - case SchemaType.Number: - comparisonKind = ComparisonKind.OperatorEquals; - hashKind = HashKind.ScalarValueType; - initializationKind = InitializationKind.SimpleAssign; - type = MakeProperNumberType(_generateJsonNumberAs); - break; + hashKind = HashKind.ScalarReferenceType; + } - case SchemaType.Integer: - comparisonKind = ComparisonKind.OperatorEquals; - hashKind = scalarValueTypeHashKind; - initializationKind = InitializationKind.SimpleAssign; - type = MakeProperIntegerType(_generateJsonIntegerAs, - propertySchema.Minimum, propertySchema.ExclusiveMinimum, - propertySchema.Maximum, propertySchema.ExclusiveMaximum, - scalarValueTypeNullable, - out namespaceName); - break; - - case SchemaType.String: + type = MakeObjectType(propertySchema, out namespaceName); + } + else if (hintTypeName == PropertyHintTypeName.Auto && propertyType == SchemaType.Array) + { + comparisonKind = ComparisonKind.Collection; + hashKind = HashKind.Collection; + initializationKind = InitializationKind.Collection; + namespaceName = "System.Collections.Generic"; // For IList. + type = MakeArrayType(entries, schemaPropertyName, propertySchema); + } + else if (propertyType == SchemaType.None) + { + SchemaType inferredType = InferSchemaTypeFromEnumValues(propertySchema.Enum); + if (inferredType == SchemaType.None) + { + comparisonKind = ComparisonKind.ObjectEquals; + hashKind = HashKind.ScalarReferenceType; + initializationKind = InitializationKind.None; + type = MakePrimitiveType(SchemaType.Object); + } + else if (inferredType == SchemaType.String) + { comparisonKind = ComparisonKind.OperatorEquals; hashKind = HashKind.ScalarReferenceType; initializationKind = InitializationKind.SimpleAssign; - type = MakePrimitiveType(propertyType); - break; - - case SchemaType.Object: - // If the schema for this property references a named type, - // the generated Init method will initialize it by cloning an object - // of that type. Otherwise, we treat this property as a System.Object - // and just initialize it by assignment. - if (propertySchema.Reference != null) - { - comparisonKind = ComparisonKind.EqualityComparerEquals; - initializationKind = InitializationKind.Clone; - hashKind = HashKind.ObjectModelType; - isOfSchemaDefinedType = true; - } - else - { - comparisonKind = ComparisonKind.ObjectEquals; - initializationKind = InitializationKind.SimpleAssign; - hashKind = HashKind.ScalarReferenceType; - } - - type = MakeObjectType(propertySchema, out namespaceName); - break; - - case SchemaType.Array: - comparisonKind = ComparisonKind.Collection; - hashKind = HashKind.Collection; - initializationKind = InitializationKind.Collection; - namespaceName = "System.Collections.Generic"; // For IList. - type = MakeArrayType(entries, schemaPropertyName, propertySchema); - break; - - case SchemaType.None: - SchemaType inferredType = InferSchemaTypeFromEnumValues(propertySchema.Enum); - if (inferredType == SchemaType.None) - { - comparisonKind = ComparisonKind.ObjectEquals; - hashKind = HashKind.ScalarReferenceType; - initializationKind = InitializationKind.None; - type = MakePrimitiveType(SchemaType.Object); - break; - - } - else if (inferredType == SchemaType.String) - { - comparisonKind = ComparisonKind.OperatorEquals; - hashKind = HashKind.ScalarReferenceType; - initializationKind = InitializationKind.SimpleAssign; - type = MakePrimitiveType(SchemaType.String); - break; - } - else - { - comparisonKind = ComparisonKind.OperatorEquals; - hashKind = HashKind.ScalarValueType; - initializationKind = InitializationKind.SimpleAssign; - type = MakePrimitiveType(inferredType); - break; - } - - default: - throw new ArgumentOutOfRangeException(nameof(propertySchema.Type)); + type = MakePrimitiveType(SchemaType.String); + } + else + { + comparisonKind = ComparisonKind.OperatorEquals; + hashKind = HashKind.ScalarValueType; + initializationKind = InitializationKind.SimpleAssign; + type = MakePrimitiveType(inferredType); + } + } + else + { + throw new ArgumentOutOfRangeException(nameof(propertySchema.Type)); } } - var propertyNameHint = _hintDictionary?.GetHint(_typeName + "." + schemaPropertyName.ToPascalCase()); - string dotNetPropertyName = propertyNameHint != null - ? propertyNameHint.DotNetPropertyName + string name = propertyHint?.Name != null + ? propertyHint.Name : schemaPropertyName.ToPascalCase(); entries.Add(new KeyValuePair( - dotNetPropertyName, + name, new PropertyInfo( propertySchema.Description, schemaPropertyName, @@ -699,12 +715,25 @@ namespace Microsoft.Json.Schema.ToDotNet return type; } - internal TypeSyntax MakeProperIntegerType(GenerateJsonIntegerOption generateJsonIntegerAs, + internal TypeSyntax MakeProperIntegerType( + string schemaPropertyName, + GenerateJsonIntegerOption generateJsonIntegerAs, + PropertyHintTypeName hintTypeName, double? minimum, bool? exclusiveMinimum, double? maximum, bool? exclusiveMaximum, bool nullable, out string namespaceName) { + GenerateJsonIntegerOption hintGenerateJsonIntegerAs; + + if (hintTypeName != PropertyHintTypeName.Auto) + { + if (Enum.TryParse(hintTypeName.ToString(), true, out hintGenerateJsonIntegerAs)) + { + generateJsonIntegerAs = hintGenerateJsonIntegerAs; + } + } + namespaceName = null; switch (generateJsonIntegerAs) @@ -745,8 +774,18 @@ namespace Microsoft.Json.Schema.ToDotNet } } - internal TypeSyntax MakeProperNumberType(GenerateJsonNumberOption generateJsonNumberAs) + internal TypeSyntax MakeProperNumberType(GenerateJsonNumberOption generateJsonNumberAs, PropertyHintTypeName hintTypeName) { + GenerateJsonNumberOption hintGenerateJsonNumberAs; + + if (hintTypeName != PropertyHintTypeName.Auto) + { + if (Enum.TryParse(hintTypeName.ToString(), true, out hintGenerateJsonNumberAs)) + { + generateJsonNumberAs = hintGenerateJsonNumberAs; + } + } + switch (generateJsonNumberAs) { case GenerateJsonNumberOption.Float: diff --git a/src/ReleaseHistory.md b/src/ReleaseHistory.md index 29fee01..ba22e01 100644 --- a/src/ReleaseHistory.md +++ b/src/ReleaseHistory.md @@ -1,6 +1,8 @@ # Microsoft Json Schema Packages -## **2.3.1** UNRELEASED +## **2.4.0** UNRELEASED +* BREAKING: Merge `HintKind`: `PropertyNameHint` and `PropertyModifiersHint` into one `PropertyHint` and change the setting `dotNetPropertyName` to `name`. [#171](https://github.com/microsoft/jschema/pull/171) +* FEATURE: Add a new setting `typeName` in `PropertyHint` to generate the specified .NET type, instead of deriving from the JSON schema. Supported values: `int`, `long`, `BigInteger`, `double`, `float`, `decimal`, `DateTime`, `Uri`, `Guid`, `bool`, `string`. [#171](https://github.com/microsoft/jschema/pull/171) * BUG: Hint file should be consistent and use Pascal case. Fix `PropertyNameHint` not functional when Pascal case is used. [#173](https://github.com/microsoft/jschema/pull/173) ## **2.3.0** [Pointer](https://www.nuget.org/packages/Microsoft.Json.Pointer/2.3.0) | [Schema](https://www.nuget.org/packages/Microsoft.Json.Schema/2.3.0)| [Schema.ToDotNet](https://www.nuget.org/packages/Microsoft.Json.Schema.ToDotNet/2.3.0)| [Schema.Validation](https://www.nuget.org/packages/Microsoft.Json.Schema.Validation/2.3.0)