From 4c2d56a6bd214ecc1c5964904bd99b9b901a329d Mon Sep 17 00:00:00 2001 From: glopesdev Date: Fri, 19 Jan 2024 17:49:53 +0000 Subject: [PATCH] Fallback for anonymous array item discriminators --- .../DiscriminatorGenerationTests.cs | 69 +++++++++++++++++++ Bonsai.Sgen/JsonSchemaExtensions.cs | 17 +++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs index 3ffe493..d6e77ea 100644 --- a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs +++ b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs @@ -280,5 +280,74 @@ public async Task GenerateFromOneOfDiscriminatorSchemaProperty_SerializerAnnotat AssertDiscriminatorAttribute(code, serializerLibraries, "kind"); CompilerTestHelper.CompileFromSource(code); } + + [TestMethod] + [DataRow(SerializerLibraries.YamlDotNet)] + [DataRow(SerializerLibraries.NewtonsoftJson)] + [DataRow(SerializerLibraries.NewtonsoftJson | SerializerLibraries.YamlDotNet)] + public async Task GenerateFromArrayItemDiscriminator_EnsureFallbackDiscriminatorBaseTypeName(SerializerLibraries serializerLibraries) + { + var schema = await JsonSchema.FromJsonAsync(@" +{ + ""$schema"": ""http://json-schema.org/draft-04/schema#"", + ""type"": ""object"", + ""title"": ""Container"", + ""properties"": { + ""Animals"": { + ""type"": ""array"", + ""items"": { + ""x-abstract"": true, + ""discriminator"": { + ""propertyName"": ""kind"", + ""mapping"": { + ""Dog"": ""#/definitions/Dog"", + ""Cat"": ""#/definitions/Cat"" + } + }, + ""oneOf"": [ + { + ""$ref"": ""#/definitions/Dog"" + }, + { + ""$ref"": ""#/definitions/Cat"" + }, + { + ""type"": ""null"" + } + ] + } + } + }, + ""definitions"": { + ""Dog"": { + ""type"": ""object"", + ""properties"": { + ""kind"": { + ""enum"": [ ""Dog"" ] + } + }, + ""required"": [ ""kind"" ] + }, + ""Cat"": { + ""type"": ""object"", + ""properties"": { + ""kind"": { + ""enum"": [ ""Cat"" ] + } + }, + ""required"": [ ""kind"" ] + } + } +} +"); + var generator = TestHelper.CreateGenerator(schema, serializerLibraries); + var code = generator.GenerateFile(); + Assert.IsTrue(code.Contains("class Dog : Anonymous"), "Derived types do not inherit from base type."); + Assert.IsTrue(!code.Contains("public enum DogKind"), "Discriminator property is repeated in derived types."); + Assert.IsTrue(code.Contains("List Animal"), "Container element type does not match base type."); + Assert.IsTrue(code.Contains("[JsonInheritanceAttribute(\"Dog\", typeof(Dog))]")); + AssertDiscriminatorAttribute(code, serializerLibraries, "kind"); + CompilerTestHelper.CompileFromSource(code); + } } } diff --git a/Bonsai.Sgen/JsonSchemaExtensions.cs b/Bonsai.Sgen/JsonSchemaExtensions.cs index 2bcf3d8..3685a55 100644 --- a/Bonsai.Sgen/JsonSchemaExtensions.cs +++ b/Bonsai.Sgen/JsonSchemaExtensions.cs @@ -26,14 +26,19 @@ protected override JsonSchema VisitSchema(JsonSchema schema, string path, string { if (schema.DiscriminatorObject != null) { - if (schema is JsonSchemaProperty schemaProperty) + if (schema is JsonSchemaProperty || schema.ParentSchema?.Item == schema) { + if (string.IsNullOrEmpty(typeNameHint)) + { + typeNameHint = "Anonymous"; + } + if (!RootObject.Definitions.ContainsKey(typeNameHint)) { var discriminatorSchema = new JsonSchema(); - discriminatorSchema.DiscriminatorObject = schemaProperty.DiscriminatorObject; - discriminatorSchema.IsAbstract = schemaProperty.IsAbstract; - foreach (var derivedSchema in schemaProperty.OneOf) + discriminatorSchema.DiscriminatorObject = schema.DiscriminatorObject; + discriminatorSchema.IsAbstract = schema.IsAbstract; + foreach (var derivedSchema in schema.OneOf) { if (derivedSchema.IsNullable(SchemaType.JsonSchema)) { @@ -45,8 +50,8 @@ protected override JsonSchema VisitSchema(JsonSchema schema, string path, string RootObject.Definitions.Add(typeNameHint, discriminatorSchema); } - schemaProperty.DiscriminatorObject = null; - schemaProperty.IsAbstract = false; + schema.DiscriminatorObject = null; + schema.IsAbstract = false; return schema; }