diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceInterfaceTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceInterfaceTests.cs index ae1b8db70..3c308b369 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceInterfaceTests.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceInterfaceTests.cs @@ -80,5 +80,27 @@ public async Task When_schema_has_base_schema_then_it_is_referenced_with_STJ() Assert.Contains("[JsonInheritanceAttribute(\"Banana\", typeof(Banana))]", code); Assert.Contains("public class JsonInheritanceConverter : System.Text.Json.Serialization.JsonConverter", code); } + + [Fact] + public async Task When_using_STJ_polymorphic_serialization_then_NSwag_inheritance_converter_and_attributes_are_not_generated() + { + //// Arrange + var json = JsonSchema.FromType(); + var data = json.ToJson(); + + var generator = new CSharpGenerator(json, new CSharpGeneratorSettings + { + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + JsonPolymorphicSerializationStyle = CSharpJsonPolymorphicSerializationStyle.SystemTextJson + }); + + //// Act + var code = generator.GenerateFile(); + + //// Assert + Assert.DoesNotContain("[JsonInheritanceConverter", code); + Assert.DoesNotContain("[JsonInheritanceAttribute", code); + Assert.DoesNotContain("public class JsonInheritanceConverter", code); + } } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceTests.cs index ac9c4e67e..a1d109f04 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceTests.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/InheritanceTests.cs @@ -156,6 +156,33 @@ public async Task When_definitions_inherit_from_root_schema() Assert.Contains("[JsonInheritanceAttribute(\"PersianCat\", typeof(PersianCat))]", code); } + [Fact] + public async Task When_definitions_inherit_from_root_schema_and_STJ_polymorphism() + { + //// Arrange + var path = GetTestDirectory() + "/References/Animal.json"; + + //// Act + var schema = await JsonSchema.FromFileAsync(path); + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + ClassStyle = CSharpClassStyle.Record, + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + JsonPolymorphicSerializationStyle = CSharpJsonPolymorphicSerializationStyle.SystemTextJson + }); + + //// Act + var code = generator.GenerateFile(); + + //// Assert + Assert.Contains("public abstract partial class Animal", code); + Assert.Contains("public partial class Cat : Animal", code); + Assert.Contains("public partial class PersianCat : Cat", code); + Assert.Contains("[System.Text.Json.Serialization.JsonPolymorphic(TypeDiscriminatorPropertyName = \"discriminator\")]", code); + Assert.Contains("[System.Text.Json.Serialization.JsonDerivedType(typeof(Cat), typeDiscriminator: \"Cat\")]", code); + Assert.Contains("[System.Text.Json.Serialization.JsonDerivedType(typeof(PersianCat), typeDiscriminator: \"PersianCat\")]", code); + } + private string GetTestDirectory() { var codeBase = Assembly.GetExecutingAssembly().CodeBase; diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs index db0bf6178..1679e563a 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs @@ -39,6 +39,7 @@ public CSharpGeneratorSettings() ClassStyle = CSharpClassStyle.Poco; JsonLibrary = CSharpJsonLibrary.NewtonsoftJson; + JsonPolymorphicSerializationStyle = CSharpJsonPolymorphicSerializationStyle.NJsonSchema; RequiredPropertiesMustBeDefined = true; GenerateDataAnnotations = true; @@ -120,6 +121,9 @@ public CSharpGeneratorSettings() /// Gets or sets the CSharp JSON library to use (default: 'NewtonsoftJson', 'SystemTextJson' is experimental/not complete). public CSharpJsonLibrary JsonLibrary { get; set; } + /// Gets or sets the CSharp JSON polymorphic serialization style (default: 'NSwag', 'SystemTextJson' is experimental/not complete). + public CSharpJsonPolymorphicSerializationStyle JsonPolymorphicSerializationStyle { get; set; } + /// Gets or sets the access modifier of generated classes and interfaces (default: 'public'). public string TypeAccessModifier { get; set; } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonPolymorphicSerializationStyle.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonPolymorphicSerializationStyle.cs new file mode 100644 index 000000000..06f76013d --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpJsonPolymorphicSerializationStyle.cs @@ -0,0 +1,12 @@ +namespace NJsonSchema.CodeGeneration.CSharp +{ + /// The CSharp JSON polymorphic serialization style. + public enum CSharpJsonPolymorphicSerializationStyle + { + /// Use NJsonSchema polymorphic serialization + NJsonSchema, + + /// Use System.Text.Json polymorphic serialization + SystemTextJson + } +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs index ef3983f1b..8b9d99cba 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs @@ -53,6 +53,9 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, /// Gets a value indicating whether to use System.Text.Json public bool UseSystemTextJson => _settings.JsonLibrary == CSharpJsonLibrary.SystemTextJson; + /// Gets a value indicating whether to use System.Text.Json polymorphic serialization + public bool UseSystemTextJsonPolymorphicSerialization => _settings.JsonPolymorphicSerializationStyle == CSharpJsonPolymorphicSerializationStyle.SystemTextJson; + /// Gets or sets the class name. public override string ClassName { get; } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs index ef18c733f..c70149a15 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs @@ -21,5 +21,8 @@ public JsonInheritanceConverterTemplateModel(CSharpGeneratorSettings settings) /// Gets a value indicating whether to use System.Text.Json public bool UseSystemTextJson => _settings.JsonLibrary == CSharpJsonLibrary.SystemTextJson; + + /// Gets a value indicating whether to use System.Text.Json polymorphic serialization + public bool UseSystemTextJsonPolymorphicSerialization => _settings.JsonPolymorphicSerializationStyle == CSharpJsonPolymorphicSerializationStyle.SystemTextJson; } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid index b04a017f0..e01e44150 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid @@ -5,14 +5,22 @@ {%- endif -%} {%- if HasDiscriminator -%} {%- if UseSystemTextJson -%} +{%- if UseSystemTextJsonPolymorphicSerialization -%} +[System.Text.Json.Serialization.JsonPolymorphic(TypeDiscriminatorPropertyName = "{{ Discriminator }}")] +{%- else -%} [JsonInheritanceConverter(typeof({{ ClassName }}), "{{ Discriminator }}")] +{%- endif -%} {%- else -%} [Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), "{{ Discriminator }}")] {%- endif -%} {%- for derivedClass in DerivedClasses -%} {%- if derivedClass.IsAbstract != true -%} +{%- if UseSystemTextJson and UseSystemTextJsonPolymorphicSerialization -%} +[System.Text.Json.Serialization.JsonDerivedType(typeof({{ derivedClass.ClassName }}), typeDiscriminator: "{{ derivedClass.Discriminator }}")] +{%- else -%} [JsonInheritanceAttribute("{{ derivedClass.Discriminator }}", typeof({{ derivedClass.ClassName }}))] {%- endif -%} +{%- endif -%} {%- endfor -%} {%- endif -%} [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttribute.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttribute.liquid index bdf15bd52..92764091a 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttribute.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttribute.liquid @@ -1,4 +1,5 @@ -[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +{%- if UseSystemTextJsonPolymorphicSerialization == false -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = true)] internal class JsonInheritanceAttribute : System.Attribute { @@ -11,4 +12,5 @@ internal class JsonInheritanceAttribute : System.Attribute public string Key { get; } public System.Type Type { get; } -} \ No newline at end of file +} +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverter.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverter.liquid index d426dfe07..2efa702e9 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverter.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverter.liquid @@ -1,4 +1,5 @@ -[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +{%- if UseSystemTextJsonPolymorphicSerialization == false -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] {%- if UseSystemTextJson -%} internal class JsonInheritanceConverterAttribute : System.Text.Json.Serialization.JsonConverterAttribute { @@ -236,3 +237,4 @@ public class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter } } {%- endif -%} +{%- endif -%} \ No newline at end of file