diff --git a/sdk/core/Azure.Core/src/Serialization/ModelJsonConverter.cs b/sdk/core/Azure.Core/src/Serialization/ModelJsonConverter.cs index 642c71687e3b..1e60f3363aa4 100644 --- a/sdk/core/Azure.Core/src/Serialization/ModelJsonConverter.cs +++ b/sdk/core/Azure.Core/src/Serialization/ModelJsonConverter.cs @@ -30,7 +30,7 @@ public ModelJsonConverter() /// /// The format to serialize to and deserialize from. public ModelJsonConverter(ModelSerializerFormat format) - : this(new ModelSerializerOptions(format)) { } + : this(ModelSerializerOptions.GetOptions(format)) { } /// /// Initializes a new instance of . diff --git a/sdk/core/Azure.Core/src/Serialization/ModelSerializer.cs b/sdk/core/Azure.Core/src/Serialization/ModelSerializer.cs index 4818144df057..3db615d1ca08 100644 --- a/sdk/core/Azure.Core/src/Serialization/ModelSerializer.cs +++ b/sdk/core/Azure.Core/src/Serialization/ModelSerializer.cs @@ -37,7 +37,7 @@ public static BinaryData Serialize(T model, ModelSerializerOptions? options = /// A representation of the model in the specified by the public static BinaryData Serialize(T model, ModelSerializerFormat format) where T : IModelSerializable - => Serialize(model, new ModelSerializerOptions(format)); + => Serialize(model, ModelSerializerOptions.GetOptions(format)); /// /// Converts the value of a model into a . @@ -67,7 +67,7 @@ public static BinaryData Serialize(object model, ModelSerializerOptions? options /// A representation of the model in the specified by the /// Throws if does not implement . public static BinaryData Serialize(object model, ModelSerializerFormat format) - => Serialize(model, new ModelSerializerOptions(format)); + => Serialize(model, ModelSerializerOptions.GetOptions(format)); /// /// Converts the into a . @@ -92,7 +92,7 @@ public static T Deserialize(BinaryData data, ModelSerializerOptions? options /// Throws if does not have a public or internal default constructor. public static T Deserialize(BinaryData data, ModelSerializerFormat format) where T : IModelSerializable - => Deserialize(data, new ModelSerializerOptions(format)); + => Deserialize(data, ModelSerializerOptions.GetOptions(format)); /// /// Converts the into a . @@ -120,7 +120,7 @@ public static object Deserialize(BinaryData data, Type returnType, ModelSerializ /// Throws if does not implement . /// Throws if does not have a public or internal default constructor. public static object Deserialize(BinaryData data, Type returnType, ModelSerializerFormat format) - => Deserialize(data, returnType, new ModelSerializerOptions(format)); + => Deserialize(data, returnType, ModelSerializerOptions.GetOptions(format)); /// /// Converts an into a . @@ -149,7 +149,7 @@ public static BinaryData ConvertToBinaryData(IModelJsonSerializable mode /// The to use. /// A binary representation of the serialized model. public static BinaryData ConvertToBinaryData(IModelJsonSerializable model, ModelSerializerFormat format) - => ConvertToBinaryData(model, new ModelSerializerOptions(format)); + => ConvertToBinaryData(model, ModelSerializerOptions.GetOptions(format)); private static IModelSerializable GetInstance(Type returnType) { diff --git a/sdk/core/Azure.Core/src/Serialization/ModelSerializerOptions.cs b/sdk/core/Azure.Core/src/Serialization/ModelSerializerOptions.cs index 2ba1a427adf0..a734b22c56f0 100644 --- a/sdk/core/Azure.Core/src/Serialization/ModelSerializerOptions.cs +++ b/sdk/core/Azure.Core/src/Serialization/ModelSerializerOptions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; namespace Azure.Core.Serialization { @@ -10,10 +11,19 @@ namespace Azure.Core.Serialization /// public class ModelSerializerOptions { + private static readonly IReadOnlyDictionary _singletonMap = new Dictionary() + { + { ModelSerializerFormat.Json, new ModelSerializerOptions(ModelSerializerFormat.Json, true) }, + { ModelSerializerFormat.Wire, new ModelSerializerOptions(ModelSerializerFormat.Wire, true) } + }; + /// /// Default options for serializing models into the format the Azure serivce is expecting. /// - public static readonly ModelSerializerOptions DefaultWireOptions = new ModelSerializerOptions(ModelSerializerFormat.Wire, true); + public static readonly ModelSerializerOptions DefaultWireOptions = _singletonMap[ModelSerializerFormat.Wire]; + + internal static ModelSerializerOptions GetOptions(ModelSerializerFormat format) + => _singletonMap.TryGetValue(format, out ModelSerializerOptions? options) ? options! : new ModelSerializerOptions(format); private bool _isFrozen; private Func? _genericTypeSerializerCreator; diff --git a/sdk/core/Azure.Core/tests/ModelSerializerOptionsTests.cs b/sdk/core/Azure.Core/tests/ModelSerializerOptionsTests.cs new file mode 100644 index 000000000000..12e2048a104b --- /dev/null +++ b/sdk/core/Azure.Core/tests/ModelSerializerOptionsTests.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Reflection; +using Azure.Core.Serialization; +using NUnit.Framework; + +namespace Azure.Core.Tests +{ + internal class ModelSerializerOptionsTests + { + [Test] + public void ValidatePropertyIsFrozen() => ValidateFrozenInstance(ModelSerializerOptions.DefaultWireOptions); + + [Test] + public void AllInstancesInMapShouldBeFrozen() + { + Dictionary optionsDictionary = typeof(ModelSerializerOptions) + .GetField("_singletonMap", BindingFlags.NonPublic | BindingFlags.Static) + .GetValue(null) as Dictionary; + foreach (var frozen in optionsDictionary.Values) + { + ValidateFrozenInstance(frozen); + } + } + + public void ValidateFrozenInstance(ModelSerializerOptions frozen) + { + Assert.Throws(() => frozen.GenericTypeSerializerCreator = type => null); + } + + [Test] + public void NewInstanceShouldNotBeFrozen() + { + ModelSerializerOptions nonFrozen = new ModelSerializerOptions(); + Assert.DoesNotThrow(() => nonFrozen.GenericTypeSerializerCreator = type => null); + } + + [Test] + public void MapAndStaticPropertySameObject() + { + Assert.IsTrue(ReferenceEquals(ModelSerializerOptions.DefaultWireOptions, ModelSerializerOptions.GetOptions(ModelSerializerFormat.Wire))); + } + + [Test] + public void MapShouldReturnSingletons() + { + Assert.IsTrue(ReferenceEquals(ModelSerializerOptions.GetOptions(ModelSerializerFormat.Wire), ModelSerializerOptions.GetOptions(ModelSerializerFormat.Wire))); + Assert.IsTrue(ReferenceEquals(ModelSerializerOptions.GetOptions(ModelSerializerFormat.Json), ModelSerializerOptions.GetOptions(ModelSerializerFormat.Json))); + } + + [Test] + public void MapShouldHaveRightValues() + { + var options = ModelSerializerOptions.GetOptions(ModelSerializerFormat.Wire); + Assert.AreEqual(ModelSerializerFormat.Wire, options.Format); + Assert.IsNull(options.GenericTypeSerializerCreator); + + options = ModelSerializerOptions.GetOptions(ModelSerializerFormat.Json); + Assert.AreEqual(ModelSerializerFormat.Json, options.Format); + Assert.IsNull(options.GenericTypeSerializerCreator); + } + } +} diff --git a/sdk/core/Azure.Core/tests/ModelSerializerTests.cs b/sdk/core/Azure.Core/tests/ModelSerializerTests.cs index f46ca31e3342..1ead9a4b089b 100644 --- a/sdk/core/Azure.Core/tests/ModelSerializerTests.cs +++ b/sdk/core/Azure.Core/tests/ModelSerializerTests.cs @@ -10,16 +10,6 @@ namespace Azure.Core.Tests.ModelSerializationTests { public class ModelSerializerTests { - [Test] - public void ValidateFrozenInstance() - { - ModelSerializerOptions frozen = ModelSerializerOptions.DefaultWireOptions; - ModelSerializerOptions nonFrozen = new ModelSerializerOptions(); - - Assert.Throws(() => frozen.GenericTypeSerializerCreator = type => null); - Assert.DoesNotThrow(() => nonFrozen.GenericTypeSerializerCreator = type => null); - } - [Test] public void ValidateErrorIfUnknownDoesntExist() {