From 93a0f9ca8af95fd60cc79207f60e15ec121e0644 Mon Sep 17 00:00:00 2001 From: Debdatta Kunda Date: Thu, 18 Jul 2024 17:18:03 -0700 Subject: [PATCH] Code changes to hide STJ serializer implementation behind a boolean flag. --- .../src/CosmosClientOptions.cs | 21 ++- .../src/Fluent/CosmosClientBuilder.cs | 10 ++ .../CosmosSystemTextJsonSerializer.cs | 4 +- ...inqAggregateCustomSerializationBaseline.cs | 5 +- ...TranslationWithCustomSerializerBaseline.cs | 2 +- .../Contracts/DotNetSDKAPI.json | 129 +++--------------- .../CosmosClientOptionsUnitTests.cs | 13 ++ 7 files changed, 67 insertions(+), 117 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index 6bfc65a005..336887a7a8 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -392,6 +392,15 @@ public ConnectionMode ConnectionMode /// /// public bool? EnableContentResponseOnWrite { get; set; } + + /// + /// Gets or sets the boolean flag to indicate if the default STJ serializer needed to be + /// used for JSON serialization. + /// + /// + /// The default value is false + /// + public bool UseSystemTextJsonForSerialization { get; set; } = false; /// /// Gets or sets the advanced replica selection flag. The advanced replica selection logic keeps track of the replica connection @@ -583,6 +592,11 @@ public CosmosSerializer Serializer throw new ArgumentException( $"{nameof(this.Serializer)} is not compatible with {nameof(this.SerializerOptions)}. Only one can be set. "); } + + if (this.UseSystemTextJsonForSerialization) + { + throw new ArgumentException($"Cannot set a custom {nameof(this.Serializer)} when {nameof(this.UseSystemTextJsonForSerialization)} is enabled. Either specify a custom or set {nameof(this.UseSystemTextJsonForSerialization)} to the default STJ serializer."); + } this.serializerInternal = value; } @@ -833,8 +847,11 @@ internal Func GetServerCerti internal void SetSerializerIfNotConfigured(CosmosSerializer serializer) { if (this.serializerInternal == null) - { - this.serializerInternal = serializer ?? throw new ArgumentNullException(nameof(serializer)); + { + this.serializerInternal = this.UseSystemTextJsonForSerialization + ? new CosmosSystemTextJsonSerializer( + new System.Text.Json.JsonSerializerOptions()) + : serializer ?? throw new ArgumentNullException(nameof(serializer)); } } diff --git a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs index 43232aa422..96dadcadf8 100644 --- a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs +++ b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs @@ -726,6 +726,16 @@ internal CosmosClientBuilder WithPartitionLevelFailoverEnabled() this.clientOptions.EnablePartitionLevelFailover = true; return this; } + + /// + /// Enables the usage of as the default + /// serializer. + /// + internal CosmosClientBuilder WithSystemTextJsonSerializerEnabled() + { + this.clientOptions.UseSystemTextJsonForSerialization = true; + return this; + } /// /// Enables SDK to inject fault. Used for testing applications. diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs index 3575782665..ac5550b128 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs @@ -13,7 +13,7 @@ namespace Microsoft.Azure.Cosmos /// /// This class provides a default implementation of System.Text.Json Cosmos Linq Serializer. /// - public class CosmosSystemTextJsonSerializer : CosmosLinqSerializer + internal class CosmosSystemTextJsonSerializer : CosmosLinqSerializer { /// /// A read-only instance of . @@ -25,7 +25,7 @@ public class CosmosSystemTextJsonSerializer : CosmosLinqSerializer /// with the default values for the Cosmos SDK /// /// An instance of containing the json serialization options. - public CosmosSystemTextJsonSerializer( + internal CosmosSystemTextJsonSerializer( JsonSerializerOptions jsonSerializerOptions) { this.jsonSerializerOptions = jsonSerializerOptions; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Linq/LinqAggregateCustomSerializationBaseline.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Linq/LinqAggregateCustomSerializationBaseline.cs index ac686b31e1..caa79fbd44 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Linq/LinqAggregateCustomSerializationBaseline.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Linq/LinqAggregateCustomSerializationBaseline.cs @@ -29,7 +29,6 @@ public class LinqAggregateCustomSerializationBaseline : BaselineTests cosmosClientBuilder.WithCustomSerializer(stjCosmosSerializer)); + => cosmosClientBuilder.WithSystemTextJsonSerializerEnabled()); // Set a callback to get the handle of the last executed query to do the verification // This is neede because aggregate queries return type is a scalar so it can't be used diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationWithCustomSerializerBaseline.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationWithCustomSerializerBaseline.cs index 1224f48074..8a4bd7e254 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationWithCustomSerializerBaseline.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationWithCustomSerializerBaseline.cs @@ -57,7 +57,7 @@ public async static Task Initialize(TestContext textContext) TestDb = await CosmosClient.CreateDatabaseAsync(dbName); CosmosDefaultSTJClient = TestCommon.CreateCosmosClient((cosmosClientBuilder) - => cosmosClientBuilder.WithCustomSerializer(new CosmosSystemTextJsonSerializer(new JsonSerializerOptions()))); + => cosmosClientBuilder.WithSystemTextJsonSerializerEnabled()); string dbNameSTJ = $"{nameof(LinqTranslationBaselineTests)}-{Guid.NewGuid():N}"; TestDbSTJDefault = await CosmosDefaultSTJClient.CreateDatabaseAsync(dbNameSTJ); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index 9a2189520f..c428e1046d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -2711,11 +2711,23 @@ ], "MethodInfo": "Boolean get_LimitToEndpoint();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "Boolean get_UseSystemTextJsonForSerialization()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": { + "Type": "Method", + "Attributes": [ + "CompilerGeneratedAttribute" + ], + "MethodInfo": "Boolean get_UseSystemTextJsonForSerialization();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "Boolean LimitToEndpoint": { "Type": "Property", "Attributes": [], "MethodInfo": "Boolean LimitToEndpoint;CanRead:True;CanWrite:True;Boolean get_LimitToEndpoint();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;Void set_LimitToEndpoint(Boolean);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "Boolean UseSystemTextJsonForSerialization": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Boolean UseSystemTextJsonForSerialization;CanRead:True;CanWrite:True;Boolean get_UseSystemTextJsonForSerialization();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;Void set_UseSystemTextJsonForSerialization(Boolean);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "Int32 GatewayModeMaxConnectionLimit": { "Type": "Property", "Attributes": [], @@ -3165,6 +3177,13 @@ ], "MethodInfo": "Void set_TokenCredentialBackgroundRefreshInterval(System.Nullable`1[System.TimeSpan]);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "Void set_UseSystemTextJsonForSerialization(Boolean)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": { + "Type": "Method", + "Attributes": [ + "CompilerGeneratedAttribute" + ], + "MethodInfo": "Void set_UseSystemTextJsonForSerialization(Boolean);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "Void set_WebProxy(System.Net.IWebProxy)": { "Type": "Method", "Attributes": [], @@ -3407,34 +3426,7 @@ "NestedTypes": {} }, "Microsoft.Azure.Cosmos.CosmosLinqSerializer;Microsoft.Azure.Cosmos.CosmosSerializer;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { - "Subclasses": { - "Microsoft.Azure.Cosmos.CosmosSystemTextJsonSerializer;Microsoft.Azure.Cosmos.CosmosLinqSerializer;IsAbstract:False;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { - "Subclasses": {}, - "Members": { - "System.IO.Stream ToStream[T](T)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.IO.Stream ToStream[T](T);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "System.String SerializeMemberName(System.Reflection.MemberInfo)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - }, - "T FromStream[T](System.IO.Stream)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "T FromStream[T](System.IO.Stream);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "Void .ctor(System.Text.Json.JsonSerializerOptions)": { - "Type": "Constructor", - "Attributes": [], - "MethodInfo": "[Void .ctor(System.Text.Json.JsonSerializerOptions), Void .ctor(System.Text.Json.JsonSerializerOptions)]" - } - }, - "NestedTypes": {} - } - }, + "Subclasses": {}, "Members": { "System.String SerializeMemberName(System.Reflection.MemberInfo)": { "Type": "Method", @@ -3685,65 +3677,12 @@ "Microsoft.Azure.Cosmos.CosmosSerializer;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": { "Microsoft.Azure.Cosmos.CosmosLinqSerializer;Microsoft.Azure.Cosmos.CosmosSerializer;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { - "Subclasses": { - "Microsoft.Azure.Cosmos.CosmosSystemTextJsonSerializer;Microsoft.Azure.Cosmos.CosmosLinqSerializer;IsAbstract:False;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { - "Subclasses": {}, - "Members": { - "System.IO.Stream ToStream[T](T)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.IO.Stream ToStream[T](T);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "System.String SerializeMemberName(System.Reflection.MemberInfo)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - }, - "T FromStream[T](System.IO.Stream)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "T FromStream[T](System.IO.Stream);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "Void .ctor(System.Text.Json.JsonSerializerOptions)": { - "Type": "Constructor", - "Attributes": [], - "MethodInfo": "[Void .ctor(System.Text.Json.JsonSerializerOptions), Void .ctor(System.Text.Json.JsonSerializerOptions)]" - } - }, - "NestedTypes": {} - } - }, - "Members": { - "System.String SerializeMemberName(System.Reflection.MemberInfo)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - } - }, - "NestedTypes": {} - }, - "Microsoft.Azure.Cosmos.CosmosSystemTextJsonSerializer;Microsoft.Azure.Cosmos.CosmosLinqSerializer;IsAbstract:False;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { - "System.IO.Stream ToStream[T](T)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.IO.Stream ToStream[T](T);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, "System.String SerializeMemberName(System.Reflection.MemberInfo)": { "Type": "Method", "Attributes": [], - "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - }, - "T FromStream[T](System.IO.Stream)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "T FromStream[T](System.IO.Stream);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "Void .ctor(System.Text.Json.JsonSerializerOptions)": { - "Type": "Constructor", - "Attributes": [], - "MethodInfo": "[Void .ctor(System.Text.Json.JsonSerializerOptions), Void .ctor(System.Text.Json.JsonSerializerOptions)]" + "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" } }, "NestedTypes": {} @@ -3763,32 +3702,6 @@ }, "NestedTypes": {} }, - "Microsoft.Azure.Cosmos.CosmosSystemTextJsonSerializer;Microsoft.Azure.Cosmos.CosmosLinqSerializer;IsAbstract:False;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { - "Subclasses": {}, - "Members": { - "System.IO.Stream ToStream[T](T)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.IO.Stream ToStream[T](T);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "System.String SerializeMemberName(System.Reflection.MemberInfo)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.String SerializeMemberName(System.Reflection.MemberInfo);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - }, - "T FromStream[T](System.IO.Stream)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "T FromStream[T](System.IO.Stream);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:True;IsConstructor:False;IsFinal:False;" - }, - "Void .ctor(System.Text.Json.JsonSerializerOptions)": { - "Type": "Constructor", - "Attributes": [], - "MethodInfo": "[Void .ctor(System.Text.Json.JsonSerializerOptions), Void .ctor(System.Text.Json.JsonSerializerOptions)]" - } - }, - "NestedTypes": {} - }, "Microsoft.Azure.Cosmos.CosmosThresholdOptions;System.Object;IsAbstract:False;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs index 293c3b14ab..9fdf6061c9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs @@ -501,6 +501,19 @@ public void ThrowOnCustomSerializerWithSerializerOptions() options.Serializer = new CosmosJsonDotNetSerializer(); } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void ThrowOnCustomSerializerWithSTJSerializerEnabled() + { + CosmosClientOptions options = new CosmosClientOptions() + { + Serializer = new CosmosJsonDotNetSerializer() + }; + + options.SerializerOptions = new CosmosSerializationOptions(); + options.UseSystemTextJsonForSerialization = true; + } [TestMethod] [ExpectedException(typeof(ArgumentNullException))]