diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs index 3bbae4561..32a828c5b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; namespace Microsoft.OpenApi.Models @@ -20,7 +21,7 @@ public class OpenApiDiscriminator : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold mappings between payload values and schema names or references. /// - public IDictionary? Mapping { get; set; } = new Dictionary(); + public IDictionary? Mapping { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. @@ -38,7 +39,7 @@ public OpenApiDiscriminator() { } public OpenApiDiscriminator(OpenApiDiscriminator discriminator) { PropertyName = discriminator?.PropertyName ?? PropertyName; - Mapping = discriminator?.Mapping != null ? new Dictionary(discriminator.Mapping) : null; + Mapping = discriminator?.Mapping != null ? new Dictionary(discriminator.Mapping) : null; Extensions = discriminator?.Extensions != null ? new Dictionary(discriminator.Extensions) : null; } @@ -80,7 +81,13 @@ private void SerializeInternal(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.PropertyName, PropertyName); // mapping - writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, (w, s) => w.WriteValue(s)); + writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, (w, s) => + { + if (!string.IsNullOrEmpty(s.Reference.ReferenceV3) && s.Reference.ReferenceV3 is not null) + { + w.WriteValue(s.Reference.ReferenceV3); + } + }); } /// diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDiscriminatorDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDiscriminatorDeserializer.cs index 1493283c0..21d8b4171 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDiscriminatorDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDiscriminatorDeserializer.cs @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Linq; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V3 @@ -22,7 +24,7 @@ internal static partial class OpenApiV3Deserializer }, { "mapping", - (o, n, _) => o.Mapping = n.CreateSimpleMap(LoadString).Where(kv => kv.Value is not null).ToDictionary(kv => kv.Key, kv => kv.Value!) + (o, n, doc) => o.Mapping = n.CreateSimpleMap((node) => LoadMapping(node, doc)) } }; @@ -40,5 +42,11 @@ public static OpenApiDiscriminator LoadDiscriminator(ParseNode node, OpenApiDocu return discriminator; } + public static OpenApiSchemaReference LoadMapping(ParseNode node, OpenApiDocument hostDocument) + { + var pointer = node.GetScalarValue() ?? throw new InvalidOperationException("Could not get a pointer reference"); + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); + } } } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index d568b327c..364eb1d54 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -5,11 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; -using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Properties; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V3 @@ -62,7 +60,8 @@ public OpenApiV3VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiServer)] = OpenApiV3Deserializer.LoadServer, [typeof(OpenApiServerVariable)] = OpenApiV3Deserializer.LoadServerVariable, [typeof(OpenApiTag)] = OpenApiV3Deserializer.LoadTag, - [typeof(OpenApiXml)] = OpenApiV3Deserializer.LoadXml + [typeof(OpenApiXml)] = OpenApiV3Deserializer.LoadXml, + [typeof(OpenApiSchemaReference)] = OpenApiV3Deserializer.LoadMapping }; public OpenApiDocument LoadDocument(RootNode rootNode) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs index e94f408d2..7eb288fd2 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDiscriminatorDeserializer.cs @@ -2,6 +2,7 @@ using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; namespace Microsoft.OpenApi.Reader.V31 @@ -22,9 +23,9 @@ internal static partial class OpenApiV31Deserializer } }, { - "mapping", (o, n, _) => + "mapping", (o, n, doc) => { - o.Mapping = n.CreateSimpleMap(LoadString).Where(kv => kv.Value is not null).ToDictionary(kv => kv.Key, kv => kv.Value!); + o.Mapping = n.CreateSimpleMap((node) => LoadMapping(node, doc)); } } }; @@ -47,5 +48,12 @@ public static OpenApiDiscriminator LoadDiscriminator(ParseNode node, OpenApiDocu return discriminator; } + + public static OpenApiSchemaReference LoadMapping(ParseNode node, OpenApiDocument hostDocument) + { + var pointer = node.GetScalarValue() ?? throw new InvalidOperationException("Could not get a pointer reference"); + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); + } } } diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs index bb6cac930..3e010be9b 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs @@ -5,11 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; -using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Properties; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V3; @@ -61,7 +59,8 @@ public OpenApiV31VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiServer)] = OpenApiV31Deserializer.LoadServer, [typeof(OpenApiServerVariable)] = OpenApiV31Deserializer.LoadServerVariable, [typeof(OpenApiTag)] = OpenApiV31Deserializer.LoadTag, - [typeof(OpenApiXml)] = OpenApiV31Deserializer.LoadXml + [typeof(OpenApiXml)] = OpenApiV31Deserializer.LoadXml, + [typeof(OpenApiSchemaReference)] = OpenApiV31Deserializer.LoadMapping }; public OpenApiDocument LoadDocument(RootNode rootNode) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs index 1629e1939..f1b047f08 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.IO; using System.Threading.Tasks; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Xunit; @@ -25,19 +27,21 @@ public async Task ParseBasicDiscriminatorShouldSucceed() memoryStream.Position = 0; // Act - var discriminator = OpenApiModelFactory.Load(memoryStream, OpenApiSpecVersion.OpenApi3_0, OpenApiConstants.Yaml, new(), out var diagnostic, SettingsFixture.ReaderSettings); + var openApiDocument = new OpenApiDocument(); + var discriminator = OpenApiModelFactory.Load(memoryStream, OpenApiSpecVersion.OpenApi3_0, OpenApiConstants.Yaml, openApiDocument, out var diagnostic, SettingsFixture.ReaderSettings); // Assert Assert.Equivalent( - new OpenApiDiscriminator - { - PropertyName = "pet_type", - Mapping = + new OpenApiDiscriminator + { + PropertyName = "pet_type", + Mapping = { - ["puppy"] = "#/components/schemas/Dog", - ["kitten"] = "Cat" + ["puppy"] = new OpenApiSchemaReference("Dog", openApiDocument), + ["kitten"] = new OpenApiSchemaReference("Cat" , openApiDocument, "https://gigantic-server.com/schemas/animals.json"), + ["monster"] = new OpenApiSchemaReference("schema.json" , openApiDocument, "https://gigantic-server.com/schemas/Monster/schema.json") } - }, discriminator); + }, discriminator); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDiscriminator/basicDiscriminator.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDiscriminator/basicDiscriminator.yaml index 7397462f3..21e6adc6c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDiscriminator/basicDiscriminator.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDiscriminator/basicDiscriminator.yaml @@ -1,4 +1,5 @@ propertyName: pet_type mapping: puppy: '#/components/schemas/Dog' - kitten: Cat \ No newline at end of file + kitten: https://gigantic-server.com/schemas/animals.json#/components/schemas/Cat + monster: https://gigantic-server.com/schemas/Monster/schema.json \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 0d691d05e..755a9e17e 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -699,7 +699,7 @@ namespace Microsoft.OpenApi.Models public OpenApiDiscriminator() { } public OpenApiDiscriminator(Microsoft.OpenApi.Models.OpenApiDiscriminator discriminator) { } public System.Collections.Generic.IDictionary? Extensions { get; set; } - public System.Collections.Generic.IDictionary? Mapping { get; set; } + public System.Collections.Generic.IDictionary? Mapping { get; set; } public string? PropertyName { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }