Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e0f3773
feat: use lazy get for collection initialization to reduce resource a…
MaggieKimani1 Mar 24, 2025
3b370e5
chore: use Lazy<T> pattern; preserve null values
MaggieKimani1 Mar 25, 2025
ef7a150
chore: replicate for collections in other components
MaggieKimani1 Mar 25, 2025
205e6a1
chore: remove unnecessary usings
MaggieKimani1 Mar 25, 2025
915e747
fix: revert lazy initialization; remove collection initialization
MaggieKimani1 Mar 26, 2025
0a65a54
chore: initialize collections to prevent NREs
MaggieKimani1 Mar 26, 2025
00e0913
chore: fix failing tests
MaggieKimani1 Mar 26, 2025
0921b0d
chore: merge remote-tracking branch 'origin/feat/memory-perf-improvem…
MaggieKimani1 Mar 26, 2025
796d49c
chore: revert changes
MaggieKimani1 Mar 26, 2025
08cc754
chore: merge main into current branch
MaggieKimani1 Apr 1, 2025
6fff3c5
chore: remove default collection initialization across all models; cl…
MaggieKimani1 Apr 1, 2025
1fa4647
chore: merge main into current branch
MaggieKimani1 Apr 2, 2025
4e97803
chore: clean up code; initialize collections where applicable
MaggieKimani1 Apr 3, 2025
eabd01d
chore: more cleanup
MaggieKimani1 Apr 3, 2025
c035940
chore: move assignment within the condition
MaggieKimani1 Apr 3, 2025
a28aa21
chore: replace interface with concrete type
MaggieKimani1 Apr 6, 2025
5686de4
chore: simplify collection initialization
MaggieKimani1 Apr 7, 2025
ccfeab1
Update src/Microsoft.OpenApi/Models/OpenApiPathItem.cs
MaggieKimani1 Apr 7, 2025
ad46bdb
chore: implement PR feedback
MaggieKimani1 Apr 7, 2025
d12efaf
chore: pull changes in remote branch
MaggieKimani1 Apr 7, 2025
cb879e3
chore: reverts casing change
baywet Apr 8, 2025
e8dc71e
Merge branch 'main' into feat/memory-perf-improvements
baywet Apr 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -32,10 +33,8 @@ public static void AddExtension<T>(this T element, string name, IOpenApiExtensio
throw new OpenApiException(string.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name));
}

if (element.Extensions is not null)
{
element.Extensions[name] = Utils.CheckArgumentNull(any);
}
element.Extensions ??= new Dictionary<string, IOpenApiExtension>();
element.Extensions[name] = Utils.CheckArgumentNull(any);
}
}
}
40 changes: 20 additions & 20 deletions src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,19 +173,19 @@
public bool WriteOnly { get; set; }

/// <inheritdoc />
public IList<IOpenApiSchema>? AllOf { get; set; } = [];
public IList<IOpenApiSchema>? AllOf { get; set; }

/// <inheritdoc />
public IList<IOpenApiSchema>? OneOf { get; set; } = [];
public IList<IOpenApiSchema>? OneOf { get; set; }

/// <inheritdoc />
public IList<IOpenApiSchema>? AnyOf { get; set; } = [];
public IList<IOpenApiSchema>? AnyOf { get; set; }

/// <inheritdoc />
public IOpenApiSchema? Not { get; set; }

/// <inheritdoc />
public ISet<string>? Required { get; set; } = new HashSet<string>();
public ISet<string>? Required { get; set; }

/// <inheritdoc />
public IOpenApiSchema? Items { get; set; }
Expand All @@ -200,10 +200,10 @@
public bool? UniqueItems { get; set; }

/// <inheritdoc />
public IDictionary<string, IOpenApiSchema>? Properties { get; set; } = new Dictionary<string, IOpenApiSchema>(StringComparer.Ordinal);
public IDictionary<string, IOpenApiSchema>? Properties { get; set; }

/// <inheritdoc />
public IDictionary<string, IOpenApiSchema>? PatternProperties { get; set; } = new Dictionary<string, IOpenApiSchema>(StringComparer.Ordinal);
public IDictionary<string, IOpenApiSchema>? PatternProperties { get; set; }

/// <inheritdoc />
public int? MaxProperties { get; set; }
Expand All @@ -227,10 +227,10 @@
public IList<JsonNode>? Examples { get; set; }

/// <inheritdoc />
public IList<JsonNode>? Enum { get; set; } = new List<JsonNode>();
public IList<JsonNode>? Enum { get; set; }

/// <inheritdoc />
public bool UnevaluatedProperties { get; set;}
public bool UnevaluatedProperties { get; set; }

/// <inheritdoc />
public OpenApiExternalDocs? ExternalDocs { get; set; }
Expand All @@ -242,16 +242,16 @@
public OpenApiXml? Xml { get; set; }

/// <inheritdoc />
public IDictionary<string, IOpenApiExtension>? Extensions { get; set; } = new Dictionary<string, IOpenApiExtension>();
public IDictionary<string, IOpenApiExtension>? Extensions { get; set; }

/// <inheritdoc />
public IDictionary<string, JsonNode>? UnrecognizedKeywords { get; set; } = new Dictionary<string, JsonNode>();
public IDictionary<string, JsonNode>? UnrecognizedKeywords { get; set; }

/// <inheritdoc />
public IDictionary<string, object>? Annotations { get; set; }

/// <inheritdoc />
public IDictionary<string, ISet<string>>? DependentRequired { get; set; } = new Dictionary<string, ISet<string>>();
public IDictionary<string, ISet<string>>? DependentRequired { get; set; }

/// <summary>
/// Parameterless constructor
Expand All @@ -262,7 +262,7 @@
/// Initializes a copy of <see cref="IOpenApiSchema"/> object
/// </summary>
/// <param name="schema">The schema object to copy from.</param>
internal OpenApiSchema(IOpenApiSchema schema)

Check warning on line 265 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this constructor to reduce its Cognitive Complexity from 20 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
Utils.CheckArgumentNull(schema);
Title = schema.Title ?? Title;
Expand Down Expand Up @@ -309,7 +309,7 @@
MinProperties = schema.MinProperties ?? MinProperties;
AdditionalPropertiesAllowed = schema.AdditionalPropertiesAllowed;
AdditionalProperties = schema.AdditionalProperties?.CreateShallowCopy();
Discriminator = schema.Discriminator != null ? new(schema.Discriminator) : null;
Discriminator = schema.Discriminator != null ? new(schema.Discriminator) : null;
Example = schema.Example != null ? JsonNodeCloneHelper.Clone(schema.Example) : null;
Examples = schema.Examples != null ? new List<JsonNode>(schema.Examples) : null;
Enum = schema.Enum != null ? new List<JsonNode>(schema.Enum) : null;
Expand All @@ -334,7 +334,7 @@
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer));
}

private static void SerializeBounds(IOpenApiWriter writer, OpenApiSpecVersion version, string propertyName, string exclusivePropertyName, string isExclusivePropertyName, decimal? value, decimal? exclusiveValue, bool? isExclusiveValue)

Check warning on line 337 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Method has 8 parameters, which is greater than the 7 authorized. (https://rules.sonarsource.com/csharp/RSPEC-107)
{
if (version >= OpenApiSpecVersion.OpenApi3_1)
{
Expand Down Expand Up @@ -421,9 +421,9 @@
writer.WriteProperty(OpenApiConstants.MinProperties, MinProperties);

// required
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) =>
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) =>
{
if (!string.IsNullOrEmpty(s) && s is not null)

Check warning on line 426 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Change this condition so that it does not always evaluate to 'True'. (https://rules.sonarsource.com/csharp/RSPEC-2589)
{
w.WriteValue(s);
}
Expand Down Expand Up @@ -502,7 +502,7 @@
// Unrecognized keywords
if (UnrecognizedKeywords is not null && UnrecognizedKeywords.Any())
{
writer.WriteOptionalMap(OpenApiConstants.UnrecognizedKeywords, UnrecognizedKeywords, (w,s) => w.WriteAny(s));
writer.WriteOptionalMap(OpenApiConstants.UnrecognizedKeywords, UnrecognizedKeywords, (w, s) => w.WriteAny(s));
}

writer.WriteEndObject();
Expand Down Expand Up @@ -665,9 +665,9 @@
writer.WriteProperty(OpenApiConstants.MinProperties, MinProperties);

// required
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) =>
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) =>
{
if (!string.IsNullOrEmpty(s) && s is not null)

Check warning on line 670 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Change this condition so that it does not always evaluate to 'True'. (https://rules.sonarsource.com/csharp/RSPEC-2589)
{
w.WriteValue(s);
}
Expand Down Expand Up @@ -744,12 +744,12 @@
writer.WriteEndObject();
}

private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version)

Check warning on line 747 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
// check whether nullable is true for upcasting purposes
var isNullable = (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) ||
Extensions is not null &&
Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) &&
Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) &&
nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode } &&
jsonNode.GetValueKind() is JsonValueKind.True;
if (type is null)
Expand All @@ -761,7 +761,7 @@
}
else if (!HasMultipleTypes(type.Value))
{

switch (version)
{
case OpenApiSpecVersion.OpenApi3_1 when isNullable:
Expand Down Expand Up @@ -794,13 +794,13 @@
select flag).ToList();
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) =>
{
foreach(var item in s.ToIdentifiers())
foreach (var item in s.ToIdentifiers())
{
w.WriteValue(item);
}
});
}
}
}
}

private static bool IsPowerOfTwo(int x)
Expand All @@ -824,9 +824,9 @@
select flag.ToFirstIdentifier()).ToList();
if (list.Count > 1)
{
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) =>
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) =>
{
if (!string.IsNullOrEmpty(s) && s is not null)

Check warning on line 829 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Change this condition so that it does not always evaluate to 'True'. (https://rules.sonarsource.com/csharp/RSPEC-2589)
{
w.WriteValue(s);
}
Expand All @@ -844,7 +844,7 @@
private static readonly Array jsonSchemaTypeValues = System.Enum.GetValues(typeof(JsonSchemaType));
#endif

private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter writer, OpenApiSpecVersion version)

Check warning on line 847 in src/Microsoft.OpenApi/Models/OpenApiSchema.cs

View workflow job for this annotation

GitHub Actions / Build

Make 'DowncastTypeArrayToV2OrV3' a static method. (https://rules.sonarsource.com/csharp/RSPEC-2325)
{
/* If the array has one non-null value, emit Type as string
* If the array has one null value, emit x-nullable as true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Nodes;

namespace Microsoft.OpenApi.Reader.V31
{
internal static partial class OpenApiV31Deserializer
{
private static readonly FixedFieldMap<OpenApiSchema> _openApiSchemaFixedFields = new()

Check warning on line 19 in src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this field to reduce its Cognitive Complexity from 52 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)

Check warning on line 19 in src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this field to reduce its Cognitive Complexity from 52 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
{
"title",
Expand Down Expand Up @@ -202,7 +203,7 @@
{
var list = n.CreateSimpleList((n2, p) => n2.GetScalarValue(), doc);
JsonSchemaType combinedType = 0;
foreach(var type in list)

Check warning on line 206 in src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs

View workflow job for this annotation

GitHub Actions / Build

Loops should be simplified using the "Where" LINQ method (https://rules.sonarsource.com/csharp/RSPEC-3267)
{
if (type is not null)
{
Expand Down Expand Up @@ -382,8 +383,9 @@
{
propertyNode.ParseField(schema, _openApiSchemaFixedFields, _openApiSchemaPatternFields, hostDocument);
}
else if (schema.UnrecognizedKeywords is not null && propertyNode.JsonNode is not null)
else if (propertyNode.JsonNode is not null)
{
schema.UnrecognizedKeywords ??= new Dictionary<string, JsonNode>(StringComparer.Ordinal);
schema.UnrecognizedKeywords[propertyNode.Name] = propertyNode.JsonNode;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static bool ValidateChildSchemaAgainstDiscriminator(IOpenApiSchema schema
{
if (discriminatorName is not null)
{
if (!schema.Required?.Contains(discriminatorName) ?? false)
if (schema.Required is null || !schema.Required.Contains(discriminatorName))
{
// recursively check nested schema.OneOf, schema.AnyOf or schema.AllOf and their required fields for the discriminator
if (schema.OneOf?.Count != 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ public void ParseHeaderWithEnumShouldSucceed()
Type = JsonSchemaType.Number,
Format = "float",
Enum =
{
[
new OpenApiAny(7).Node,
new OpenApiAny(8).Node,
new OpenApiAny(9).Node
}
]
}
}, options => options.IgnoringCyclicReferences()
.Excluding((IMemberInfo memberInfo) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ public async Task SerializesBodyReferencesWorks()
openApiDocument.AddComponent("UserSchema", new OpenApiSchema
{
Type = JsonSchemaType.Object,
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["name"] = new OpenApiSchema
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,11 @@ public void ParseParameterWithEnumShouldSucceed()
Type = JsonSchemaType.Number,
Format = "float",
Enum =
{
new OpenApiAny(7).Node,
new OpenApiAny(8).Node,
new OpenApiAny(9).Node
}
[
new OpenApiAny(7).Node,
new OpenApiAny(8).Node,
new OpenApiAny(9).Node
]
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
using System.Linq;
using System.Net.Http;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.Interfaces;
using Microsoft.OpenApi.Reader.ParseNodes;
using Microsoft.OpenApi.Reader.V2;
using Microsoft.OpenApi.Writers;
using Xunit;

namespace Microsoft.OpenApi.Readers.Tests.V2Tests
Expand Down Expand Up @@ -69,7 +71,7 @@ public class OpenApiPathItemTests
Schema = new OpenApiSchema()
{
Type = JsonSchemaType.Object,
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["name"] = new OpenApiSchema()
{
Expand All @@ -93,7 +95,7 @@ public class OpenApiPathItemTests
Schema = new OpenApiSchema()
{
Type = JsonSchemaType.Object,
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["name"] = new OpenApiSchema()
{
Expand Down Expand Up @@ -175,7 +177,7 @@ public class OpenApiPathItemTests
Schema = new OpenApiSchema()
{
Type = JsonSchemaType.Object,
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["name"] = new OpenApiSchema()
{
Expand Down Expand Up @@ -204,7 +206,7 @@ public class OpenApiPathItemTests
Schema = new OpenApiSchema()
{
Type = JsonSchemaType.Object,
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["name"] = new OpenApiSchema()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ public async Task SerializesDoubleHopeReferences()
{
Type = JsonSchemaType.Object,
Description = "A pet",
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["id"] = new OpenApiSchema
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ public async Task ParseQueryParameterWithObjectTypeAndContentShouldSucceed()
Schema = new OpenApiSchema()
{
Type = JsonSchemaType.Object,
Required =
Required = new HashSet<string>
{
"lat",
"long"
},
Properties =
Properties = new Dictionary<string, IOpenApiSchema>
{
["lat"] = new OpenApiSchema()
{
Expand Down
Loading
Loading