Skip to content

Commit

Permalink
fix: a bug where 3.0 downcast of type null would not work
Browse files Browse the repository at this point in the history
  • Loading branch information
baywet committed Jan 31, 2025
1 parent c637cc4 commit ac05342
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 27 deletions.
49 changes: 31 additions & 18 deletions src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Helpers;
using Microsoft.OpenApi.Interfaces;
Expand Down Expand Up @@ -355,12 +357,6 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
// default
writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d));

// nullable
if (version is OpenApiSpecVersion.OpenApi3_0)
{
writer.WriteProperty(OpenApiConstants.Nullable, Nullable, false);
}

// discriminator
writer.WriteOptionalObject(OpenApiConstants.Discriminator, Discriminator, callback);

Expand Down Expand Up @@ -635,20 +631,33 @@ private void SerializeAsV2(

private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version)
{
// check whether nullable is true for upcasting purposes
var isNullable = Nullable ||
Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) &&
nullExtRawValue is OpenApiAny openApiAny &&
openApiAny.Node is JsonNode jsonNode &&
jsonNode.GetValueKind() is JsonValueKind.True;
if (type is null)
{
return;
}
if (!HasMultipleTypes(type.Value))
{
// check whether nullable is true for upcasting purposes
if (version is OpenApiSpecVersion.OpenApi3_1 && (Nullable || Extensions.ContainsKey(OpenApiConstants.NullableExtension)))
if (version is OpenApiSpecVersion.OpenApi3_0 && isNullable)
{
UpCastSchemaTypeToV31(type, writer);
writer.WriteProperty(OpenApiConstants.Nullable, true);
}
else
}
else if (!HasMultipleTypes(type.Value))
{

switch (version)
{
writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier());
case OpenApiSpecVersion.OpenApi3_1 when isNullable:
UpCastSchemaTypeToV31(type.Value, writer);
break;
case OpenApiSpecVersion.OpenApi3_0 when isNullable:
writer.WriteProperty(OpenApiConstants.Nullable, true);
goto default;
default:
writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier());
break;
}
}
else
Expand All @@ -663,6 +672,10 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer,
var list = (from JsonSchemaType flag in jsonSchemaTypeValues
where type.Value.HasFlag(flag)
select flag).ToList();
if (Nullable && !list.Contains(JsonSchemaType.Null))
{
list.Add(JsonSchemaType.Null);
}
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier()));
}
}
Expand All @@ -680,12 +693,12 @@ private static bool HasMultipleTypes(JsonSchemaType schemaType)
schemaTypeNumeric != (int)JsonSchemaType.Null;
}

private void UpCastSchemaTypeToV31(JsonSchemaType? type, IOpenApiWriter writer)
private void UpCastSchemaTypeToV31(JsonSchemaType type, IOpenApiWriter writer)
{
// create a new array and insert the type and "null" as values
Type = type | JsonSchemaType.Null;
var temporaryType = type | JsonSchemaType.Null;
var list = (from JsonSchemaType? flag in jsonSchemaTypeValues// Check if the flag is set in 'type' using a bitwise AND operation
where Type.Value.HasFlag(flag)
where temporaryType.HasFlag(flag)
select flag.ToIdentifier()).ToList();
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"maximum": 42,
"minimum": 10,
"exclusiveMinimum": true,
"nullable": true,
"type": "integer",
"default": 15,
"nullable": true,
"externalDocs": {
"url": "http://example.com/externalDocs"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","default":15,"nullable":true,"externalDocs":{"url":"http://example.com/externalDocs"}}
{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"maximum": 42,
"minimum": 10,
"exclusiveMinimum": true,
"nullable": true,
"type": "integer",
"default": 15,
"nullable": true,
"externalDocs": {
"url": "http://example.com/externalDocs"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","default":15,"nullable":true,"externalDocs":{"url":"http://example.com/externalDocs"}}
{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}}
10 changes: 5 additions & 5 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ public async Task SerializeAdvancedSchemaNumberAsV3JsonWorks()
"maximum": 42,
"minimum": 10,
"exclusiveMinimum": true,
"nullable": true,
"type": "integer",
"default": 15,
"nullable": true,
"externalDocs": {
"url": "http://example.com/externalDocs"
}
Expand All @@ -268,6 +268,7 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks()
"""
{
"title": "title1",
"nullable": true,
"properties": {
"property1": {
"properties": {
Expand Down Expand Up @@ -296,7 +297,6 @@ public async Task SerializeAdvancedSchemaObjectAsV3JsonWorks()
}
}
},
"nullable": true,
"externalDocs": {
"url": "http://example.com/externalDocs"
}
Expand All @@ -320,6 +320,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks()
"""
{
"title": "title1",
"nullable": true,
"allOf": [
{
"title": "title2",
Expand All @@ -335,6 +336,7 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks()
},
{
"title": "title3",
"nullable": true,
"properties": {
"property3": {
"properties": {
Expand All @@ -347,11 +349,9 @@ public async Task SerializeAdvancedSchemaWithAllOfAsV3JsonWorks()
"minLength": 2,
"type": "string"
}
},
"nullable": true
}
}
],
"nullable": true,
"externalDocs": {
"url": "http://example.com/externalDocs"
}
Expand Down

0 comments on commit ac05342

Please sign in to comment.