From 4217e9c366bbe6f2f83e1b8a6bcf9399bed00834 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:39:57 +0200 Subject: [PATCH 01/11] Improving serialization Fixed #310 --- .../KiotaJsonSerializer.Serialization.cs | 16 ++++++++++++++-- .../KiotaSerializer.Serialization.cs | 5 +++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index a35df57a..9cadf912 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -20,9 +20,21 @@ public static partial class KiotaJsonSerializer /// /// Type of the object to serialize /// The object to serialize. + /// Backing store keeps track of changes, setting this to false will give you the full item. /// The serialized representation as a stream. - public static Stream SerializeAsStream(T value) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value); + public static Stream SerializeAsStream(T value, bool useBackingStore = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, useBackingStore); + + /// + /// Serializes the specified object as a string based JSON stream. + /// + /// The type of the value to serialize. + /// The object to serialize. + /// A flag indicating whether to use a backing store for serialization. + /// A containing the serialized JSON data. + + public static Stream SerializeAsJsonStream(this T value, bool useBackingStore = true) where T : IParsable + => SerializeAsStream(value, useBackingStore); /// /// Serializes the given object into a string based on the content type. diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index 1a01f2e5..00020f37 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -25,11 +25,12 @@ public static partial class KiotaSerializer /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. + /// Backing store keeps track of changes, setting this to false will give you the full item. /// The serialized representation as a stream. - public static Stream SerializeAsStream(string contentType, T value) where T : IParsable + public static Stream SerializeAsStream(string contentType, T value, bool useBackingStore = true) where T : IParsable { using var writer = GetSerializationWriter(contentType, value); - writer.WriteObjectValue(string.Empty, value); + writer.WriteObjectValue(useBackingStore ? string.Empty : null, value); return writer.GetSerializedContent(); } /// From d83cb537c1c8384c5870c1ae01702c6928eb4cf2 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:04:11 +0200 Subject: [PATCH 02/11] Feedback by @baywet applied --- .../KiotaJsonSerializer.Serialization.cs | 28 +++++++++++++------ .../KiotaSerializer.Serialization.cs | 11 ++++---- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index 9cadf912..a6025ee2 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -20,21 +20,21 @@ public static partial class KiotaJsonSerializer /// /// Type of the object to serialize /// The object to serialize. - /// Backing store keeps track of changes, setting this to false will give you the full item. + /// By default you'll only get the changed properties /// The serialized representation as a stream. - public static Stream SerializeAsStream(T value, bool useBackingStore = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, useBackingStore); + public static Stream SerializeAsStream(T value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); /// /// Serializes the specified object as a string based JSON stream. /// /// The type of the value to serialize. /// The object to serialize. - /// A flag indicating whether to use a backing store for serialization. + /// By default you'll only get the changed properties /// A containing the serialized JSON data. - public static Stream SerializeAsJsonStream(this T value, bool useBackingStore = true) where T : IParsable - => SerializeAsStream(value, useBackingStore); + public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable + => SerializeAsStream(value, serializeOnlyChangedValues); /// /// Serializes the given object into a string based on the content type. @@ -61,9 +61,21 @@ public static Task SerializeAsStringAsync(T value, CancellationToken /// /// Type of the object to serialize /// The object to serialize. + /// By default you'll only get the changed properties /// The serialized representation as a stream. - public static Stream SerializeAsStream(IEnumerable value) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value); + public static Stream SerializeAsStream(IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the specified object as a string based JSON stream. + /// + /// The type of the object to serialize. + /// The enumerable of objects to serialize. + /// By default you'll only get the changed properties + /// A containing the serialized JSON data. + + public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable + => SerializeAsStream(value, serializeOnlyChangedValues); /// /// Serializes the given object into a string based on the content type. diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index 00020f37..6ac58c6b 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -25,12 +25,12 @@ public static partial class KiotaSerializer /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. - /// Backing store keeps track of changes, setting this to false will give you the full item. + /// By default you'll only get the changed properties. /// The serialized representation as a stream. - public static Stream SerializeAsStream(string contentType, T value, bool useBackingStore = true) where T : IParsable + public static Stream SerializeAsStream(string contentType, T value, bool serializeOnlyChangedValues = true) where T : IParsable { using var writer = GetSerializationWriter(contentType, value); - writer.WriteObjectValue(useBackingStore ? string.Empty : null, value); + writer.WriteObjectValue(serializeOnlyChangedValues ? string.Empty : null, value); return writer.GetSerializedContent(); } /// @@ -65,11 +65,12 @@ public static Task SerializeAsStringAsync(string contentType, T value /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. + /// By default you'll only get the changed properties. /// The serialized representation as a stream. - public static Stream SerializeAsStream(string contentType, IEnumerable value) where T : IParsable + public static Stream SerializeAsStream(string contentType, IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable { using var writer = GetSerializationWriter(contentType, value); - writer.WriteCollectionOfObjectValues(string.Empty, value); + writer.WriteCollectionOfObjectValues(serializeOnlyChangedValues ? string.Empty : null, value); return writer.GetSerializedContent(); } /// From 14452aa7daa5749b845d45cb580551b528fa4764 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:18:28 +0200 Subject: [PATCH 03/11] Setting the InitializationCompleted --- .../KiotaSerializer.Serialization.cs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index 6ac58c6b..49a7cc42 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -7,6 +7,8 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.Kiota.Abstractions.Store; + #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -29,9 +31,21 @@ public static partial class KiotaSerializer /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, T value, bool serializeOnlyChangedValues = true) where T : IParsable { + bool restoreInitializationCompleted = false; + if(!serializeOnlyChangedValues && value is IBackedModel backedModel) + { + // reset the initialization completed flag to ensure all properties are serialized + restoreInitializationCompleted = backedModel.BackingStore.InitializationCompleted; + backedModel.BackingStore.InitializationCompleted = false; + } using var writer = GetSerializationWriter(contentType, value); - writer.WriteObjectValue(serializeOnlyChangedValues ? string.Empty : null, value); - return writer.GetSerializedContent(); + writer.WriteObjectValue(null, value); + var stream = writer.GetSerializedContent(); + if(restoreInitializationCompleted) + { + (value as IBackedModel)!.BackingStore.InitializationCompleted = true; + } + return stream; } /// /// Serializes the given object into a string based on the content type. @@ -69,9 +83,21 @@ public static Task SerializeAsStringAsync(string contentType, T value /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable { + bool resetInitializationCompleted = false; + if(!serializeOnlyChangedValues && value is IBackedModel backedModel) + { + // reset the initialization completed flag to ensure all properties are serialized + backedModel.BackingStore.InitializationCompleted = false; + resetInitializationCompleted = true; + } using var writer = GetSerializationWriter(contentType, value); - writer.WriteCollectionOfObjectValues(serializeOnlyChangedValues ? string.Empty : null, value); - return writer.GetSerializedContent(); + writer.WriteCollectionOfObjectValues(null, value); + var stream = writer.GetSerializedContent(); + if(resetInitializationCompleted) + { + (value as IBackedModel)!.BackingStore.InitializationCompleted = true; + } + return stream; } /// /// Serializes the given object into a string based on the content type. From 9c33bbde0d09cd5a8fa32220414ab9444d7724c0 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:48:36 +0200 Subject: [PATCH 04/11] Return concrete writer when want to skip backing store --- .../ISerializationWriterFactory.cs | 3 +- .../KiotaJsonSerializer.Serialization.cs | 39 +++++++++--- .../KiotaSerializer.Serialization.cs | 63 ++++++++++--------- .../SerializationWriterFactoryRegistry.cs | 4 +- .../SerializationWriterProxyFactory.cs | 9 ++- ...ingStoreSerializationWriterProxyFactory.cs | 14 +++++ .../form/FormSerializationWriterFactory.cs | 2 +- .../json/JsonSerializationWriterFactory.cs | 3 +- .../MultipartSerializationWriterFactory.cs | 2 +- .../text/TextSerializationWriterFactory.cs | 2 +- tests/abstractions/MultipartBodyTests.cs | 4 +- tests/abstractions/RequestInformationTests.cs | 10 +-- .../SerializationHelpersTests.cs | 8 +-- ...SerializationWriterFactoryRegistryTests.cs | 4 +- 14 files changed, 107 insertions(+), 60 deletions(-) diff --git a/src/abstractions/serialization/ISerializationWriterFactory.cs b/src/abstractions/serialization/ISerializationWriterFactory.cs index ba619cc9..eb8f6931 100644 --- a/src/abstractions/serialization/ISerializationWriterFactory.cs +++ b/src/abstractions/serialization/ISerializationWriterFactory.cs @@ -17,7 +17,8 @@ public interface ISerializationWriterFactory /// Creates a new instance for the given content type. /// /// The content type for which a serialization writer should be created. + /// By default a backing store is used, and you'll only get changed properties /// A new instance for the given content type. - ISerializationWriter GetSerializationWriter(string contentType); + ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true); } } diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index a6025ee2..1de9e1b1 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -7,6 +7,8 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using System.ComponentModel; + #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -20,7 +22,7 @@ public static partial class KiotaJsonSerializer /// /// Type of the object to serialize /// The object to serialize. - /// By default you'll only get the changed properties + /// By default a backing store is used, and you'll only get changed properties /// The serialized representation as a stream. public static Stream SerializeAsStream(T value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); @@ -30,7 +32,7 @@ public static Stream SerializeAsStream(T value, bool serializeOnlyChangedValu /// /// The type of the value to serialize. /// The object to serialize. - /// By default you'll only get the changed properties + /// By default a backing store is used, and you'll only get changed properties /// A containing the serialized JSON data. public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable @@ -53,15 +55,26 @@ public static string SerializeAsString(T value) where T : IParsable /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. - public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] + public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(value, true, cancellationToken); + + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); /// /// Serializes the given object into a string based on the content type. /// /// Type of the object to serialize /// The object to serialize. - /// By default you'll only get the changed properties + /// By default a backing store is used, and you'll only get changed properties /// The serialized representation as a stream. public static Stream SerializeAsStream(IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); @@ -71,7 +84,7 @@ public static Stream SerializeAsStream(IEnumerable value, bool serializeOn /// /// The type of the object to serialize. /// The enumerable of objects to serialize. - /// By default you'll only get the changed properties + /// By default a backing store is used, and you'll only get changed properties /// A containing the serialized JSON data. public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable @@ -93,7 +106,17 @@ public static string SerializeAsString(IEnumerable value) where T : IParsa /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. - public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] + public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(value, true, cancellationToken); + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); } \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index 49a7cc42..004b730b 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -8,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Kiota.Abstractions.Store; +using System.ComponentModel; + #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; @@ -31,20 +33,9 @@ public static partial class KiotaSerializer /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, T value, bool serializeOnlyChangedValues = true) where T : IParsable { - bool restoreInitializationCompleted = false; - if(!serializeOnlyChangedValues && value is IBackedModel backedModel) - { - // reset the initialization completed flag to ensure all properties are serialized - restoreInitializationCompleted = backedModel.BackingStore.InitializationCompleted; - backedModel.BackingStore.InitializationCompleted = false; - } - using var writer = GetSerializationWriter(contentType, value); + using var writer = GetSerializationWriter(contentType, value, serializeOnlyChangedValues); writer.WriteObjectValue(null, value); var stream = writer.GetSerializedContent(); - if(restoreInitializationCompleted) - { - (value as IBackedModel)!.BackingStore.InitializationCompleted = true; - } return stream; } /// @@ -68,9 +59,20 @@ public static string SerializeAsString(string contentType, T value) where T : /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. - public static Task SerializeAsStringAsync(string contentType, T value, CancellationToken cancellationToken = default) where T : IParsable + [EditorBrowsable(EditorBrowsableState.Never)] + public static Task SerializeAsStringAsync(string contentType, T value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(contentType, value, true, cancellationToken); + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// Content type to serialize the object to + /// The object to serialize. + /// By default you'll only get the changed properties. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(string contentType, T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable { - using var stream = SerializeAsStream(contentType, value); + using var stream = SerializeAsStream(contentType, value, serializeOnlyChangedValues); return GetStringFromStreamAsync(stream, cancellationToken); } /// @@ -83,20 +85,9 @@ public static Task SerializeAsStringAsync(string contentType, T value /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable { - bool resetInitializationCompleted = false; - if(!serializeOnlyChangedValues && value is IBackedModel backedModel) - { - // reset the initialization completed flag to ensure all properties are serialized - backedModel.BackingStore.InitializationCompleted = false; - resetInitializationCompleted = true; - } - using var writer = GetSerializationWriter(contentType, value); + using var writer = GetSerializationWriter(contentType, value, serializeOnlyChangedValues); writer.WriteCollectionOfObjectValues(null, value); var stream = writer.GetSerializedContent(); - if(resetInitializationCompleted) - { - (value as IBackedModel)!.BackingStore.InitializationCompleted = true; - } return stream; } /// @@ -118,13 +109,25 @@ public static string SerializeAsString(string contentType, IEnumerable val /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. + /// /// The token to monitor for cancellation requests. /// The serialized representation as a string. - public static Task SerializeAsStringAsync(string contentType, IEnumerable value, CancellationToken cancellationToken = default) where T : IParsable + public static Task SerializeAsStringAsync(string contentType, IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable { - using var stream = SerializeAsStream(contentType, value); + using var stream = SerializeAsStream(contentType, value, serializeOnlyChangedValues); return GetStringFromStreamAsync(stream, cancellationToken); } + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// Content type to serialize the object to + /// The object to serialize. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + [EditorBrowsable(EditorBrowsableState.Never)] + public static Task SerializeAsStringAsync(string contentType, IEnumerable value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(contentType, value, true, cancellationToken); + [Obsolete("This method is obsolete, use the async method instead")] private static string GetStringFromStream(Stream stream) { @@ -140,10 +143,10 @@ private static async Task GetStringFromStreamAsync(Stream stream, Cancel return await reader.ReadToEndAsync().ConfigureAwait(false); #endif } - private static ISerializationWriter GetSerializationWriter(string contentType, object value) + private static ISerializationWriter GetSerializationWriter(string contentType, object value, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); if(value == null) throw new ArgumentNullException(nameof(value)); - return SerializationWriterFactoryRegistry.DefaultInstance.GetSerializationWriter(contentType); + return SerializationWriterFactoryRegistry.DefaultInstance.GetSerializationWriter(contentType, serializeOnlyChangedValues); } } \ No newline at end of file diff --git a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs index 0ffd5c25..4dbf9206 100644 --- a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs +++ b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs @@ -34,8 +34,9 @@ public string ValidContentType /// Get the relevant instance for the given content type /// /// The content type in use + /// By default a backing store is used, and you'll only get changed properties /// A instance to parse the content - public ISerializationWriter GetSerializationWriter(string contentType) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); @@ -50,6 +51,5 @@ public ISerializationWriter GetSerializationWriter(string contentType) throw new InvalidOperationException($"Content type {cleanedContentType} does not have a factory registered to be parsed"); } - } } diff --git a/src/abstractions/serialization/SerializationWriterProxyFactory.cs b/src/abstractions/serialization/SerializationWriterProxyFactory.cs index 76e14d5c..71f02f1b 100644 --- a/src/abstractions/serialization/SerializationWriterProxyFactory.cs +++ b/src/abstractions/serialization/SerializationWriterProxyFactory.cs @@ -15,7 +15,11 @@ public class SerializationWriterProxyFactory : ISerializationWriterFactory /// The valid content type for the /// public string ValidContentType { get { return _concrete.ValidContentType; } } - private readonly ISerializationWriterFactory _concrete; + + /// + /// The concrete factory to wrap. + /// + protected readonly ISerializationWriterFactory _concrete; private readonly Action _onBefore; private readonly Action _onAfter; private readonly Action _onStartSerialization; @@ -40,8 +44,9 @@ public SerializationWriterProxyFactory(ISerializationWriterFactory concrete, /// Creates a new instance for the given content type. /// /// The content type for which a serialization writer should be created. + /// By default a backing store is used, and you'll only get changed properties /// A new instance for the given content type. - public ISerializationWriter GetSerializationWriter(string contentType) + public virtual ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { var writer = _concrete.GetSerializationWriter(contentType); var originalBefore = writer.OnBeforeObjectSerialization; diff --git a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs index 2f82038a..b03a56e8 100644 --- a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs +++ b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs @@ -37,5 +37,19 @@ public BackingStoreSerializationWriterProxyFactory(ISerializationWriterFactory c } }) { } + + /// + /// Get the serialization writer for the given content type. + /// + /// The content type for which a serialization writer should be created. + /// By default a backing store is used, and you'll only get changed properties + /// + public override ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + { + if(serializeOnlyChangedValues) + return base.GetSerializationWriter(contentType); + + return _concrete.GetSerializationWriter(contentType); + } } } diff --git a/src/serialization/form/FormSerializationWriterFactory.cs b/src/serialization/form/FormSerializationWriterFactory.cs index ca4e72c7..7fb5f89d 100644 --- a/src/serialization/form/FormSerializationWriterFactory.cs +++ b/src/serialization/form/FormSerializationWriterFactory.cs @@ -8,7 +8,7 @@ public class FormSerializationWriterFactory : ISerializationWriterFactory /// public string ValidContentType => "application/x-www-form-urlencoded"; /// - public ISerializationWriter GetSerializationWriter(string contentType) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/json/JsonSerializationWriterFactory.cs b/src/serialization/json/JsonSerializationWriterFactory.cs index 6591df58..c6313b87 100644 --- a/src/serialization/json/JsonSerializationWriterFactory.cs +++ b/src/serialization/json/JsonSerializationWriterFactory.cs @@ -40,8 +40,9 @@ public JsonSerializationWriterFactory(KiotaJsonSerializationContext kiotaJsonSer /// Get a valid for the content type /// /// The content type to search for + /// By default a backing store is used, and you'll only get changed properties /// A instance for json writing - public ISerializationWriter GetSerializationWriter(string contentType) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/multipart/MultipartSerializationWriterFactory.cs b/src/serialization/multipart/MultipartSerializationWriterFactory.cs index 7a22c3b7..8ebd8ce4 100644 --- a/src/serialization/multipart/MultipartSerializationWriterFactory.cs +++ b/src/serialization/multipart/MultipartSerializationWriterFactory.cs @@ -13,7 +13,7 @@ public class MultipartSerializationWriterFactory : ISerializationWriterFactory /// public string ValidContentType => "multipart/form-data"; /// - public ISerializationWriter GetSerializationWriter(string contentType) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/text/TextSerializationWriterFactory.cs b/src/serialization/text/TextSerializationWriterFactory.cs index f64920bb..325e1af1 100644 --- a/src/serialization/text/TextSerializationWriterFactory.cs +++ b/src/serialization/text/TextSerializationWriterFactory.cs @@ -12,7 +12,7 @@ public class TextSerializationWriterFactory : ISerializationWriterFactory public string ValidContentType { get; } = "text/plain"; /// - public ISerializationWriter GetSerializationWriter(string contentType) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/tests/abstractions/MultipartBodyTests.cs b/tests/abstractions/MultipartBodyTests.cs index d06afbdb..ca622a2c 100644 --- a/tests/abstractions/MultipartBodyTests.cs +++ b/tests/abstractions/MultipartBodyTests.cs @@ -25,7 +25,7 @@ public void KeepsFilename() jsonWriterMock.Setup(w => w.GetSerializedContent()).Returns(ms); serializationFactoryMock - .Setup(r => r.GetSerializationWriter("application/json")) + .Setup(r => r.GetSerializationWriter("application/json", true)) .Returns(jsonWriterMock.Object); requestAdapterMock @@ -67,7 +67,7 @@ public void WorksWithoutFilename() jsonWriterMock.Setup(w => w.GetSerializedContent()).Returns(ms); serializationFactoryMock - .Setup(r => r.GetSerializationWriter("application/json")) + .Setup(r => r.GetSerializationWriter("application/json", It.IsAny())) .Returns(jsonWriterMock.Object); requestAdapterMock diff --git a/tests/abstractions/RequestInformationTests.cs b/tests/abstractions/RequestInformationTests.cs index 7e59e6e6..84913467 100644 --- a/tests/abstractions/RequestInformationTests.cs +++ b/tests/abstractions/RequestInformationTests.cs @@ -422,7 +422,7 @@ public void SetsObjectContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -442,7 +442,7 @@ public void SetsObjectCollectionContentSingleElement() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -462,7 +462,7 @@ public void SetsScalarContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -482,7 +482,7 @@ public void SetsScalarCollectionContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -524,7 +524,7 @@ public void SetsBoundaryOnMultipartBody() var requestAdapterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); var serializationWriterMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); // Given var multipartBody = new MultipartBody diff --git a/tests/abstractions/Serialization/SerializationHelpersTests.cs b/tests/abstractions/Serialization/SerializationHelpersTests.cs index 0b119223..05cbcd93 100644 --- a/tests/abstractions/Serialization/SerializationHelpersTests.cs +++ b/tests/abstractions/Serialization/SerializationHelpersTests.cs @@ -31,7 +31,7 @@ public async Task SerializesObject() var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("{'id':'123'}"))); var mockSerializationWriterFactory = new Mock(); - mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new TestEntity() @@ -41,7 +41,7 @@ public async Task SerializesObject() Assert.Equal("{'id':'123'}", result); - mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny()), Times.Once); + mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny(), It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.WriteObjectValue(It.IsAny(), It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.GetSerializedContent(), Times.Once); } @@ -51,7 +51,7 @@ public async Task SerializesObjectCollection() var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("[{'id':'123'}]"))); var mockSerializationWriterFactory = new Mock(); - mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new List { @@ -63,7 +63,7 @@ public async Task SerializesObjectCollection() Assert.Equal("[{'id':'123'}]", result); - mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny()), Times.Once); + mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny(), It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.WriteCollectionOfObjectValues(It.IsAny(), It.IsAny>()), Times.Once); mockSerializationWriter.Verify(x => x.GetSerializedContent(), Times.Once); } diff --git a/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs b/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs index 1e571dd6..f582abed 100644 --- a/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs +++ b/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs @@ -30,7 +30,7 @@ public void ReturnsExpectedRootNodeForRegisteredContentType() using var testStream = new MemoryStream(Encoding.UTF8.GetBytes("test input")); var mockSerializationWriterFactory = new Mock(); var mockSerializationWriter = new Mock(); - mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(streamContentType)).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(streamContentType, It.IsAny())).Returns(mockSerializationWriter.Object); _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(streamContentType, mockSerializationWriterFactory.Object); // Act var serializationWriter = _serializationWriterFactoryRegistry.GetSerializationWriter(streamContentType); @@ -45,7 +45,7 @@ public void ReturnsExpectedSerializationWriterForVendorSpecificContentTyp() var applicationJsonContentType = "application/json"; var mockSerializationWriterFactory = new Mock(); var mockSerializationWriter = new Mock(); - mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(applicationJsonContentType)).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(applicationJsonContentType, It.IsAny())).Returns(mockSerializationWriter.Object); _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(applicationJsonContentType, mockSerializationWriterFactory.Object); // Act var serializationWriter = _serializationWriterFactoryRegistry.GetSerializationWriter("application/vnd+json"); From 7aa31001324d31bcb313e535fa5a5075f640b770 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 1 Aug 2024 17:04:16 +0200 Subject: [PATCH 05/11] Reverting source breaking change --- .../ISerializationWriterFactory.cs | 3 +- .../SerializationWriterFactoryRegistry.cs | 44 ++++++++++++++++++- .../SerializationWriterProxyFactory.cs | 3 +- ...ingStoreSerializationWriterProxyFactory.cs | 2 +- .../form/FormSerializationWriterFactory.cs | 2 +- .../json/JsonSerializationWriterFactory.cs | 3 +- .../MultipartSerializationWriterFactory.cs | 2 +- .../text/TextSerializationWriterFactory.cs | 2 +- tests/abstractions/MultipartBodyTests.cs | 4 +- tests/abstractions/RequestInformationTests.cs | 10 ++--- .../SerializationHelpersTests.cs | 8 ++-- ...SerializationWriterFactoryRegistryTests.cs | 4 +- 12 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/abstractions/serialization/ISerializationWriterFactory.cs b/src/abstractions/serialization/ISerializationWriterFactory.cs index eb8f6931..ba619cc9 100644 --- a/src/abstractions/serialization/ISerializationWriterFactory.cs +++ b/src/abstractions/serialization/ISerializationWriterFactory.cs @@ -17,8 +17,7 @@ public interface ISerializationWriterFactory /// Creates a new instance for the given content type. /// /// The content type for which a serialization writer should be created. - /// By default a backing store is used, and you'll only get changed properties /// A new instance for the given content type. - ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true); + ISerializationWriter GetSerializationWriter(string contentType); } } diff --git a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs index 4dbf9206..bc71d7fd 100644 --- a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs +++ b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs @@ -34,9 +34,8 @@ public string ValidContentType /// Get the relevant instance for the given content type /// /// The content type in use - /// By default a backing store is used, and you'll only get changed properties /// A instance to parse the content - public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); @@ -51,5 +50,46 @@ public ISerializationWriter GetSerializationWriter(string contentType, bool seri throw new InvalidOperationException($"Content type {cleanedContentType} does not have a factory registered to be parsed"); } + + /// + /// Get the relevant instance for the given content type + /// + /// The content type in use + /// If will only return changed values, otherwise will return the full object + /// A instance to parse the content + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues) + { + if(serializeOnlyChangedValues) + return GetSerializationWriter(contentType); + + var factory = GetSerializationWriterFactory(contentType); + if(factory is Store.BackingStoreSerializationWriterProxyFactory backingStoreFactory) + return backingStoreFactory.GetSerializationWriter(contentType, false); + + return factory.GetSerializationWriter(contentType); + } + + /// + /// Get the relevant instance for the given content type + /// + /// The content type in use + /// + /// + /// + private ISerializationWriterFactory GetSerializationWriterFactory(string contentType) + { + if(string.IsNullOrEmpty(contentType)) + throw new ArgumentNullException(nameof(contentType)); + + var vendorSpecificContentType = contentType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0]; + if(ContentTypeAssociatedFactories.TryGetValue(vendorSpecificContentType, out var vendorFactory)) + return vendorFactory; + + var cleanedContentType = ParseNodeFactoryRegistry.contentTypeVendorCleanupRegex.Replace(vendorSpecificContentType, string.Empty); + if(ContentTypeAssociatedFactories.TryGetValue(cleanedContentType, out var factory)) + return factory; + + throw new InvalidOperationException($"Content type {cleanedContentType} does not have a factory registered to be parsed"); + } } } diff --git a/src/abstractions/serialization/SerializationWriterProxyFactory.cs b/src/abstractions/serialization/SerializationWriterProxyFactory.cs index 71f02f1b..0e518534 100644 --- a/src/abstractions/serialization/SerializationWriterProxyFactory.cs +++ b/src/abstractions/serialization/SerializationWriterProxyFactory.cs @@ -44,9 +44,8 @@ public SerializationWriterProxyFactory(ISerializationWriterFactory concrete, /// Creates a new instance for the given content type. /// /// The content type for which a serialization writer should be created. - /// By default a backing store is used, and you'll only get changed properties /// A new instance for the given content type. - public virtual ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { var writer = _concrete.GetSerializationWriter(contentType); var originalBefore = writer.OnBeforeObjectSerialization; diff --git a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs index b03a56e8..79ad1cc9 100644 --- a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs +++ b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs @@ -44,7 +44,7 @@ public BackingStoreSerializationWriterProxyFactory(ISerializationWriterFactory c /// The content type for which a serialization writer should be created. /// By default a backing store is used, and you'll only get changed properties /// - public override ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues) { if(serializeOnlyChangedValues) return base.GetSerializationWriter(contentType); diff --git a/src/serialization/form/FormSerializationWriterFactory.cs b/src/serialization/form/FormSerializationWriterFactory.cs index 7fb5f89d..ca4e72c7 100644 --- a/src/serialization/form/FormSerializationWriterFactory.cs +++ b/src/serialization/form/FormSerializationWriterFactory.cs @@ -8,7 +8,7 @@ public class FormSerializationWriterFactory : ISerializationWriterFactory /// public string ValidContentType => "application/x-www-form-urlencoded"; /// - public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/json/JsonSerializationWriterFactory.cs b/src/serialization/json/JsonSerializationWriterFactory.cs index c6313b87..6591df58 100644 --- a/src/serialization/json/JsonSerializationWriterFactory.cs +++ b/src/serialization/json/JsonSerializationWriterFactory.cs @@ -40,9 +40,8 @@ public JsonSerializationWriterFactory(KiotaJsonSerializationContext kiotaJsonSer /// Get a valid for the content type /// /// The content type to search for - /// By default a backing store is used, and you'll only get changed properties /// A instance for json writing - public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/multipart/MultipartSerializationWriterFactory.cs b/src/serialization/multipart/MultipartSerializationWriterFactory.cs index 8ebd8ce4..7a22c3b7 100644 --- a/src/serialization/multipart/MultipartSerializationWriterFactory.cs +++ b/src/serialization/multipart/MultipartSerializationWriterFactory.cs @@ -13,7 +13,7 @@ public class MultipartSerializationWriterFactory : ISerializationWriterFactory /// public string ValidContentType => "multipart/form-data"; /// - public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/src/serialization/text/TextSerializationWriterFactory.cs b/src/serialization/text/TextSerializationWriterFactory.cs index 325e1af1..f64920bb 100644 --- a/src/serialization/text/TextSerializationWriterFactory.cs +++ b/src/serialization/text/TextSerializationWriterFactory.cs @@ -12,7 +12,7 @@ public class TextSerializationWriterFactory : ISerializationWriterFactory public string ValidContentType { get; } = "text/plain"; /// - public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues = true) + public ISerializationWriter GetSerializationWriter(string contentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); diff --git a/tests/abstractions/MultipartBodyTests.cs b/tests/abstractions/MultipartBodyTests.cs index ca622a2c..d06afbdb 100644 --- a/tests/abstractions/MultipartBodyTests.cs +++ b/tests/abstractions/MultipartBodyTests.cs @@ -25,7 +25,7 @@ public void KeepsFilename() jsonWriterMock.Setup(w => w.GetSerializedContent()).Returns(ms); serializationFactoryMock - .Setup(r => r.GetSerializationWriter("application/json", true)) + .Setup(r => r.GetSerializationWriter("application/json")) .Returns(jsonWriterMock.Object); requestAdapterMock @@ -67,7 +67,7 @@ public void WorksWithoutFilename() jsonWriterMock.Setup(w => w.GetSerializedContent()).Returns(ms); serializationFactoryMock - .Setup(r => r.GetSerializationWriter("application/json", It.IsAny())) + .Setup(r => r.GetSerializationWriter("application/json")) .Returns(jsonWriterMock.Object); requestAdapterMock diff --git a/tests/abstractions/RequestInformationTests.cs b/tests/abstractions/RequestInformationTests.cs index 84913467..7e59e6e6 100644 --- a/tests/abstractions/RequestInformationTests.cs +++ b/tests/abstractions/RequestInformationTests.cs @@ -422,7 +422,7 @@ public void SetsObjectContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -442,7 +442,7 @@ public void SetsObjectCollectionContentSingleElement() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -462,7 +462,7 @@ public void SetsScalarContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -482,7 +482,7 @@ public void SetsScalarCollectionContent() var requestAdapterMock = new Mock(); var serializationWriterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); var requestInfo = new RequestInformation { @@ -524,7 +524,7 @@ public void SetsBoundaryOnMultipartBody() var requestAdapterMock = new Mock(); var serializationWriterFactoryMock = new Mock(); var serializationWriterMock = new Mock(); - serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(serializationWriterMock.Object); + serializationWriterFactoryMock.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(serializationWriterMock.Object); requestAdapterMock.SetupGet(x => x.SerializationWriterFactory).Returns(serializationWriterFactoryMock.Object); // Given var multipartBody = new MultipartBody diff --git a/tests/abstractions/Serialization/SerializationHelpersTests.cs b/tests/abstractions/Serialization/SerializationHelpersTests.cs index 05cbcd93..0b119223 100644 --- a/tests/abstractions/Serialization/SerializationHelpersTests.cs +++ b/tests/abstractions/Serialization/SerializationHelpersTests.cs @@ -31,7 +31,7 @@ public async Task SerializesObject() var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("{'id':'123'}"))); var mockSerializationWriterFactory = new Mock(); - mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new TestEntity() @@ -41,7 +41,7 @@ public async Task SerializesObject() Assert.Equal("{'id':'123'}", result); - mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny(), It.IsAny()), Times.Once); + mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.WriteObjectValue(It.IsAny(), It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.GetSerializedContent(), Times.Once); } @@ -51,7 +51,7 @@ public async Task SerializesObjectCollection() var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("[{'id':'123'}]"))); var mockSerializationWriterFactory = new Mock(); - mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny(), It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new List { @@ -63,7 +63,7 @@ public async Task SerializesObjectCollection() Assert.Equal("[{'id':'123'}]", result); - mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny(), It.IsAny()), Times.Once); + mockSerializationWriterFactory.Verify(x => x.GetSerializationWriter(It.IsAny()), Times.Once); mockSerializationWriter.Verify(x => x.WriteCollectionOfObjectValues(It.IsAny(), It.IsAny>()), Times.Once); mockSerializationWriter.Verify(x => x.GetSerializedContent(), Times.Once); } diff --git a/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs b/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs index f582abed..1e571dd6 100644 --- a/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs +++ b/tests/abstractions/Serialization/SerializationWriterFactoryRegistryTests.cs @@ -30,7 +30,7 @@ public void ReturnsExpectedRootNodeForRegisteredContentType() using var testStream = new MemoryStream(Encoding.UTF8.GetBytes("test input")); var mockSerializationWriterFactory = new Mock(); var mockSerializationWriter = new Mock(); - mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(streamContentType, It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(streamContentType)).Returns(mockSerializationWriter.Object); _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(streamContentType, mockSerializationWriterFactory.Object); // Act var serializationWriter = _serializationWriterFactoryRegistry.GetSerializationWriter(streamContentType); @@ -45,7 +45,7 @@ public void ReturnsExpectedSerializationWriterForVendorSpecificContentTyp() var applicationJsonContentType = "application/json"; var mockSerializationWriterFactory = new Mock(); var mockSerializationWriter = new Mock(); - mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(applicationJsonContentType, It.IsAny())).Returns(mockSerializationWriter.Object); + mockSerializationWriterFactory.Setup(serializationWriterFactory => serializationWriterFactory.GetSerializationWriter(applicationJsonContentType)).Returns(mockSerializationWriter.Object); _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(applicationJsonContentType, mockSerializationWriterFactory.Object); // Act var serializationWriter = _serializationWriterFactoryRegistry.GetSerializationWriter("application/vnd+json"); From e69900726e078ac4e7eaf745885ec7447ca1e9f6 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Sat, 3 Aug 2024 18:51:43 +0200 Subject: [PATCH 06/11] Moved extension methods to their respective projects This way you have to include these packages as well, they will throw otherwise. --- .../KiotaJsonSerializer.Serialization.cs | 77 ++++-------------- .../KiotaSerializer.Serialization.cs | 7 +- src/serialization/form/IParsableExtensions.cs | 78 +++++++++++++++++++ src/serialization/json/IParsableExtensions.cs | 78 +++++++++++++++++++ 4 files changed, 175 insertions(+), 65 deletions(-) create mode 100644 src/serialization/form/IParsableExtensions.cs create mode 100644 src/serialization/json/IParsableExtensions.cs diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index 1de9e1b1..ac5141cf 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -17,34 +17,14 @@ namespace Microsoft.Kiota.Abstractions.Serialization; public static partial class KiotaJsonSerializer { - /// - /// Serializes the given object into a string based on the content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsStream(T value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the specified object as a string based JSON stream. - /// - /// The type of the value to serialize. - /// The object to serialize. - /// By default a backing store is used, and you'll only get changed properties - /// A containing the serialized JSON data. - - public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable - => SerializeAsStream(value, serializeOnlyChangedValues); - /// /// Serializes the given object into a string based on the content type. /// /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the async method instead")] + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [EditorBrowsable(EditorBrowsableState.Never)] public static string SerializeAsString(T value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); @@ -55,40 +35,21 @@ public static string SerializeAsString(T value) where T : IParsable /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] [EditorBrowsable(EditorBrowsableState.Never)] - public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(value, true, cancellationToken); - - /// - /// Serializes the given object into a string based on the content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsStringAsync(T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - + public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); + /// /// Serializes the given object into a string based on the content type. /// /// Type of the object to serialize /// The object to serialize. - /// By default a backing store is used, and you'll only get changed properties /// The serialized representation as a stream. - public static Stream SerializeAsStream(IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the specified object as a string based JSON stream. - /// - /// The type of the object to serialize. - /// The enumerable of objects to serialize. - /// By default a backing store is used, and you'll only get changed properties - /// A containing the serialized JSON data. - - public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable - => SerializeAsStream(value, serializeOnlyChangedValues); + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [EditorBrowsable(EditorBrowsableState.Never)] + public static Stream SerializeAsStream(IEnumerable value) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value); /// /// Serializes the given object into a string based on the content type. @@ -96,7 +57,8 @@ public static Stream SerializeAsJsonStream(this IEnumerable value, bool se /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the async method instead")] + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [EditorBrowsable(EditorBrowsableState.Never)] public static string SerializeAsString(IEnumerable value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); /// @@ -106,17 +68,10 @@ public static string SerializeAsString(IEnumerable value) where T : IParsa /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] [EditorBrowsable(EditorBrowsableState.Never)] - public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken) where T : IParsable => SerializeAsStringAsync(value, true, cancellationToken); - /// - /// Serializes the given object into a string based on the content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsStringAsync(IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); + public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken) where T : IParsable => + KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); + } \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index 004b730b..e07dda83 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -7,7 +7,6 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.Kiota.Abstractions.Store; using System.ComponentModel; @@ -29,7 +28,7 @@ public static partial class KiotaSerializer /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. - /// By default you'll only get the changed properties. + /// By default, you'll only get the changed properties. /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, T value, bool serializeOnlyChangedValues = true) where T : IParsable { @@ -67,7 +66,7 @@ public static string SerializeAsString(string contentType, T value) where T : /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. - /// By default you'll only get the changed properties. + /// By default, you'll only get the changed properties. /// The token to monitor for cancellation requests. /// The serialized representation as a string. public static Task SerializeAsStringAsync(string contentType, T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable @@ -81,7 +80,7 @@ public static Task SerializeAsStringAsync(string contentType, T value /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. - /// By default you'll only get the changed properties. + /// By default, you'll only get the changed properties. /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable { diff --git a/src/serialization/form/IParsableExtensions.cs b/src/serialization/form/IParsableExtensions.cs new file mode 100644 index 00000000..c371ff11 --- /dev/null +++ b/src/serialization/form/IParsableExtensions.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Kiota.Abstractions.Serialization; + +namespace Microsoft.Kiota.Serialization.Form; + +/// +/// Serialization extensions for IParsable objects (form url encoded) +/// +public static class IParsableExtensions +{ + private const string _formContentType = "application/x-www-form-urlencoded"; + /// + /// Serializes the given object into stream with form url encoded content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsFormStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a form url encoded string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsFormAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); + + /// + /// Serializes the given object into stream with form url encoded content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsFormStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a form url encoded string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsFormAsync(this IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); + + /// + /// Serializes the given object into stream with form url encoded content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsFormStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a form url encoded string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsFormAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); + +} \ No newline at end of file diff --git a/src/serialization/json/IParsableExtensions.cs b/src/serialization/json/IParsableExtensions.cs new file mode 100644 index 00000000..5e652873 --- /dev/null +++ b/src/serialization/json/IParsableExtensions.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Kiota.Abstractions.Serialization; + +namespace Microsoft.Kiota.Serialization.Json; + +/// +/// Serialization extensions for IParsable objects (JSON) +/// +public static class IParsableExtensions +{ + private const string _jsonContentType = "application/json"; + /// + /// Serializes the given object into stream with json content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a json string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsJsonAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); + + /// + /// Serializes the given object into stream with json content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a json string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsJsonAsync(this IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); + + /// + /// Serializes the given object into stream with json content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The serialized representation as a stream. + public static Stream SerializeAsJsonStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); + + /// + /// Serializes the given object into a json string. + /// + /// Type of the object to serialize + /// The object to serialize. + /// By default, a backing store is used, and you'll only get changed properties + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsJsonAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); + +} \ No newline at end of file From b28d52482076fe342165c0b4b77fcdc706bc8ed4 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Sat, 3 Aug 2024 22:01:47 +0200 Subject: [PATCH 07/11] Adding test that emulate new extension methods --- .../KiotaJsonSerializer.Serialization.cs | 15 ++- .../SerializationWriterFactoryRegistry.cs | 37 +++---- .../SerializationWriterProxyFactory.cs | 14 +-- ...ingStoreSerializationWriterProxyFactory.cs | 4 +- .../json/IParsableExtensionsTests.cs | 99 +++++++++++++++++++ .../json/Mocks/BackedTestEntity.cs | 40 ++++++++ 6 files changed, 175 insertions(+), 34 deletions(-) create mode 100644 tests/serialization/json/IParsableExtensionsTests.cs create mode 100644 tests/serialization/json/Mocks/BackedTestEntity.cs diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index ac5141cf..087e7e3e 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -17,6 +17,17 @@ namespace Microsoft.Kiota.Abstractions.Serialization; public static partial class KiotaJsonSerializer { + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// The serialized representation as a stream. + [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [EditorBrowsable(EditorBrowsableState.Never)] + public static Stream SerializeAsStream(T value) where T : IParsable + => KiotaSerializer.SerializeAsStream(_jsonContentType, value); + /// /// Serializes the given object into a string based on the content type. /// @@ -72,6 +83,4 @@ public static string SerializeAsString(IEnumerable value) where T : IParsa [EditorBrowsable(EditorBrowsableState.Never)] public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); - - -} \ No newline at end of file +} diff --git a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs index bc71d7fd..b4f65d1e 100644 --- a/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs +++ b/src/abstractions/serialization/SerializationWriterFactoryRegistry.cs @@ -26,30 +26,19 @@ public string ValidContentType /// Default singleton instance of the registry to be used when registering new factories that should be available by default. /// public static readonly SerializationWriterFactoryRegistry DefaultInstance = new(); + /// /// List of factories that are registered by content type. /// public ConcurrentDictionary ContentTypeAssociatedFactories { get; set; } = new(); + /// /// Get the relevant instance for the given content type /// /// The content type in use /// A instance to parse the content public ISerializationWriter GetSerializationWriter(string contentType) - { - if(string.IsNullOrEmpty(contentType)) - throw new ArgumentNullException(nameof(contentType)); - - var vendorSpecificContentType = contentType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0]; - if(ContentTypeAssociatedFactories.TryGetValue(vendorSpecificContentType, out var vendorFactory)) - return vendorFactory.GetSerializationWriter(vendorSpecificContentType); - - var cleanedContentType = ParseNodeFactoryRegistry.contentTypeVendorCleanupRegex.Replace(vendorSpecificContentType, string.Empty); - if(ContentTypeAssociatedFactories.TryGetValue(cleanedContentType, out var factory)) - return factory.GetSerializationWriter(cleanedContentType); - - throw new InvalidOperationException($"Content type {cleanedContentType} does not have a factory registered to be parsed"); - } + => GetSerializationWriter(contentType, true); /// /// Get the relevant instance for the given content type @@ -59,35 +48,39 @@ public ISerializationWriter GetSerializationWriter(string contentType) /// A instance to parse the content public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues) { - if(serializeOnlyChangedValues) - return GetSerializationWriter(contentType); - - var factory = GetSerializationWriterFactory(contentType); - if(factory is Store.BackingStoreSerializationWriterProxyFactory backingStoreFactory) - return backingStoreFactory.GetSerializationWriter(contentType, false); + var factory = GetSerializationWriterFactory(contentType, out string actualContentType); + if(!serializeOnlyChangedValues && factory is Store.BackingStoreSerializationWriterProxyFactory backingStoreFactory) + return backingStoreFactory.GetSerializationWriter(actualContentType, false); - return factory.GetSerializationWriter(contentType); + return factory.GetSerializationWriter(actualContentType); } /// /// Get the relevant instance for the given content type /// /// The content type in use + /// The content type where a writer factory is found for /// /// /// - private ISerializationWriterFactory GetSerializationWriterFactory(string contentType) + private ISerializationWriterFactory GetSerializationWriterFactory(string contentType, out string actualContentType) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType)); var vendorSpecificContentType = contentType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0]; if(ContentTypeAssociatedFactories.TryGetValue(vendorSpecificContentType, out var vendorFactory)) + { + actualContentType = vendorSpecificContentType; return vendorFactory; + } var cleanedContentType = ParseNodeFactoryRegistry.contentTypeVendorCleanupRegex.Replace(vendorSpecificContentType, string.Empty); if(ContentTypeAssociatedFactories.TryGetValue(cleanedContentType, out var factory)) + { + actualContentType = cleanedContentType; return factory; + } throw new InvalidOperationException($"Content type {cleanedContentType} does not have a factory registered to be parsed"); } diff --git a/src/abstractions/serialization/SerializationWriterProxyFactory.cs b/src/abstractions/serialization/SerializationWriterProxyFactory.cs index 0e518534..d5a59786 100644 --- a/src/abstractions/serialization/SerializationWriterProxyFactory.cs +++ b/src/abstractions/serialization/SerializationWriterProxyFactory.cs @@ -14,28 +14,28 @@ public class SerializationWriterProxyFactory : ISerializationWriterFactory /// /// The valid content type for the /// - public string ValidContentType { get { return _concrete.ValidContentType; } } + public string ValidContentType { get { return ProxiedSerializationWriterFactory.ValidContentType; } } /// - /// The concrete factory to wrap. + /// The factory that is being proxied. /// - protected readonly ISerializationWriterFactory _concrete; + protected readonly ISerializationWriterFactory ProxiedSerializationWriterFactory; private readonly Action _onBefore; private readonly Action _onAfter; private readonly Action _onStartSerialization; /// /// Creates a new proxy factory that wraps the specified concrete factory while composing the before and after callbacks. /// - /// The concrete factory to wrap. + /// The concrete factory to wrap. /// The callback to invoke before the serialization of any model object. /// The callback to invoke after the serialization of any model object. /// The callback to invoke when serialization of the entire model has started. - public SerializationWriterProxyFactory(ISerializationWriterFactory concrete, + public SerializationWriterProxyFactory(ISerializationWriterFactory factoryToWrap, Action onBeforeSerialization, Action onAfterSerialization, Action onStartSerialization) { - _concrete = concrete ?? throw new ArgumentNullException(nameof(concrete)); + ProxiedSerializationWriterFactory = factoryToWrap ?? throw new ArgumentNullException(nameof(factoryToWrap)); _onBefore = onBeforeSerialization; _onAfter = onAfterSerialization; _onStartSerialization = onStartSerialization; @@ -47,7 +47,7 @@ public SerializationWriterProxyFactory(ISerializationWriterFactory concrete, /// A new instance for the given content type. public ISerializationWriter GetSerializationWriter(string contentType) { - var writer = _concrete.GetSerializationWriter(contentType); + var writer = ProxiedSerializationWriterFactory.GetSerializationWriter(contentType); var originalBefore = writer.OnBeforeObjectSerialization; var originalAfter = writer.OnAfterObjectSerialization; var originalStart = writer.OnStartObjectSerialization; diff --git a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs index 79ad1cc9..87915a7c 100644 --- a/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs +++ b/src/abstractions/store/BackingStoreSerializationWriterProxyFactory.cs @@ -42,14 +42,14 @@ public BackingStoreSerializationWriterProxyFactory(ISerializationWriterFactory c /// Get the serialization writer for the given content type. /// /// The content type for which a serialization writer should be created. - /// By default a backing store is used, and you'll only get changed properties + /// By default, a backing store is used, and you'll only get changed properties /// public ISerializationWriter GetSerializationWriter(string contentType, bool serializeOnlyChangedValues) { if(serializeOnlyChangedValues) return base.GetSerializationWriter(contentType); - return _concrete.GetSerializationWriter(contentType); + return ProxiedSerializationWriterFactory.GetSerializationWriter(contentType); } } } diff --git a/tests/serialization/json/IParsableExtensionsTests.cs b/tests/serialization/json/IParsableExtensionsTests.cs new file mode 100644 index 00000000..71db6a41 --- /dev/null +++ b/tests/serialization/json/IParsableExtensionsTests.cs @@ -0,0 +1,99 @@ +using System.IO; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using Microsoft.Kiota.Serialization.Json.Tests.Mocks; +using Xunit; + +namespace Microsoft.Kiota.Serialization.Json.Tests +{ + public class IParsableExtensionsTests + { + private const string _jsonContentType = "application/json"; + private readonly SerializationWriterFactoryRegistry _serializationWriterFactoryRegistry; + + public IParsableExtensionsTests() + { + _serializationWriterFactoryRegistry = new SerializationWriterFactoryRegistry(); + _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(_jsonContentType, new BackingStoreSerializationWriterProxyFactory(new JsonSerializationWriterFactory())); + } + + [Theory] + [InlineData(null)] + [InlineData(true)] + [InlineData(false)] + public void GetSerializationWriter_RetunsJsonSerializationWriter(bool? serializeOnlyChangedValues) + { + // Arrange + + // Act + using var writer = serializeOnlyChangedValues.HasValue + ? _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, serializeOnlyChangedValues.Value) + : _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType); + + // Assert + Assert.NotNull(writer); + Assert.IsType(writer); + } + + [Fact] + public void GetSerializationWriterSerializedChangedTrue_RetunsEmptyJson() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); + + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); + + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{}", serializedContent); + } + + [Fact] + public void GetSerializationWriterSerializedChangedTrue_ChangedName_ReturnsJustName() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + testUser.Name = "Stephan"; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); + + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); + + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{\"name\":\"Stephan\"}", serializedContent); + } + + [Fact] + public void GetSerializationWriterSerializedChangedFalse_SerializesEntireObject() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, false); + + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); + + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{\"id\":\"1\",\"name\":\"testUser\"}", serializedContent); + } + + private static string GetStringFromStream(Stream stream) + { + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + } +} diff --git a/tests/serialization/json/Mocks/BackedTestEntity.cs b/tests/serialization/json/Mocks/BackedTestEntity.cs new file mode 100644 index 00000000..6ff41b8b --- /dev/null +++ b/tests/serialization/json/Mocks/BackedTestEntity.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; + +namespace Microsoft.Kiota.Serialization.Json.Tests.Mocks +{ + public class BackedTestEntity : IParsable, IBackedModel + { + public BackedTestEntity() + { + BackingStore = new InMemoryBackingStore(); + } + + public IBackingStore BackingStore { get; private set; } + + public string Id + { + get { return BackingStore?.Get("id"); } + set { BackingStore?.Set("id", value); } + } + public string Name + { + get { return BackingStore?.Get("name"); } + set { BackingStore?.Set("name", value); } + } + + public IDictionary> GetFieldDeserializers() => + new Dictionary> { + { "id", n => { Id = n.GetStringValue(); } }, + { "name", n => { Name = n.GetStringValue(); } }, + }; + public void Serialize(ISerializationWriter writer) + { + _ = writer ?? throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("name", Name); + } + } +} From 8919b34b7795b174174eb831ca0ec85a1ab0b7ec Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Mon, 5 Aug 2024 11:59:54 +0300 Subject: [PATCH 08/11] dotnet format --- .../KiotaJsonSerializer.Serialization.cs | 8 +- .../KiotaSerializer.Serialization.cs | 2 +- src/serialization/form/IParsableExtensions.cs | 10 +- src/serialization/json/IParsableExtensions.cs | 10 +- .../json/IParsableExtensionsTests.cs | 150 +++++++++--------- .../json/Mocks/BackedTestEntity.cs | 50 +++--- 6 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index 087e7e3e..2916d20e 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Threading; using System.Threading.Tasks; -using System.ComponentModel; #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; @@ -27,7 +27,7 @@ public static partial class KiotaJsonSerializer [EditorBrowsable(EditorBrowsableState.Never)] public static Stream SerializeAsStream(T value) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value); - + /// /// Serializes the given object into a string based on the content type. /// @@ -48,9 +48,9 @@ public static string SerializeAsString(T value) where T : IParsable /// The serialized representation as a string. [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] [EditorBrowsable(EditorBrowsableState.Never)] - public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable + public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); - + /// /// Serializes the given object into a string based on the content type. /// diff --git a/src/abstractions/serialization/KiotaSerializer.Serialization.cs b/src/abstractions/serialization/KiotaSerializer.Serialization.cs index e07dda83..b331212b 100644 --- a/src/abstractions/serialization/KiotaSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaSerializer.Serialization.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Threading; using System.Threading.Tasks; -using System.ComponentModel; #if NET5_0_OR_GREATER diff --git a/src/serialization/form/IParsableExtensions.cs b/src/serialization/form/IParsableExtensions.cs index c371ff11..f95eaf8c 100644 --- a/src/serialization/form/IParsableExtensions.cs +++ b/src/serialization/form/IParsableExtensions.cs @@ -21,7 +21,7 @@ public static class IParsableExtensions /// The serialized representation as a stream. public static Stream SerializeAsFormStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a form url encoded string. /// @@ -32,7 +32,7 @@ public static Stream SerializeAsFormStream(this T value, bool serializeOnlyCh /// The serialized representation as a string. public static Task SerializeAsFormAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); - + /// /// Serializes the given object into stream with form url encoded content type. /// @@ -42,7 +42,7 @@ public static Task SerializeAsFormAsync(this T value, bool serializeO /// The serialized representation as a stream. public static Stream SerializeAsFormStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a form url encoded string. /// @@ -63,7 +63,7 @@ public static Task SerializeAsFormAsync(this IEnumerable value, bo /// The serialized representation as a stream. public static Stream SerializeAsFormStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a form url encoded string. /// @@ -74,5 +74,5 @@ public static Stream SerializeAsFormStream(this T[] value, bool serializeOnly /// The serialized representation as a string. public static Task SerializeAsFormAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); - + } \ No newline at end of file diff --git a/src/serialization/json/IParsableExtensions.cs b/src/serialization/json/IParsableExtensions.cs index 5e652873..710fa2e5 100644 --- a/src/serialization/json/IParsableExtensions.cs +++ b/src/serialization/json/IParsableExtensions.cs @@ -21,7 +21,7 @@ public static class IParsableExtensions /// The serialized representation as a stream. public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a json string. /// @@ -32,7 +32,7 @@ public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyCh /// The serialized representation as a string. public static Task SerializeAsJsonAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - + /// /// Serializes the given object into stream with json content type. /// @@ -42,7 +42,7 @@ public static Task SerializeAsJsonAsync(this T value, bool serializeO /// The serialized representation as a stream. public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a json string. /// @@ -63,7 +63,7 @@ public static Task SerializeAsJsonAsync(this IEnumerable value, bo /// The serialized representation as a stream. public static Stream SerializeAsJsonStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - + /// /// Serializes the given object into a json string. /// @@ -74,5 +74,5 @@ public static Stream SerializeAsJsonStream(this T[] value, bool serializeOnly /// The serialized representation as a string. public static Task SerializeAsJsonAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - + } \ No newline at end of file diff --git a/tests/serialization/json/IParsableExtensionsTests.cs b/tests/serialization/json/IParsableExtensionsTests.cs index 71db6a41..4f5a9410 100644 --- a/tests/serialization/json/IParsableExtensionsTests.cs +++ b/tests/serialization/json/IParsableExtensionsTests.cs @@ -6,94 +6,94 @@ namespace Microsoft.Kiota.Serialization.Json.Tests { - public class IParsableExtensionsTests - { - private const string _jsonContentType = "application/json"; - private readonly SerializationWriterFactoryRegistry _serializationWriterFactoryRegistry; - - public IParsableExtensionsTests() + public class IParsableExtensionsTests { - _serializationWriterFactoryRegistry = new SerializationWriterFactoryRegistry(); - _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(_jsonContentType, new BackingStoreSerializationWriterProxyFactory(new JsonSerializationWriterFactory())); - } + private const string _jsonContentType = "application/json"; + private readonly SerializationWriterFactoryRegistry _serializationWriterFactoryRegistry; - [Theory] - [InlineData(null)] - [InlineData(true)] - [InlineData(false)] - public void GetSerializationWriter_RetunsJsonSerializationWriter(bool? serializeOnlyChangedValues) - { - // Arrange + public IParsableExtensionsTests() + { + _serializationWriterFactoryRegistry = new SerializationWriterFactoryRegistry(); + _serializationWriterFactoryRegistry.ContentTypeAssociatedFactories.TryAdd(_jsonContentType, new BackingStoreSerializationWriterProxyFactory(new JsonSerializationWriterFactory())); + } - // Act - using var writer = serializeOnlyChangedValues.HasValue - ? _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, serializeOnlyChangedValues.Value) - : _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType); + [Theory] + [InlineData(null)] + [InlineData(true)] + [InlineData(false)] + public void GetSerializationWriter_RetunsJsonSerializationWriter(bool? serializeOnlyChangedValues) + { + // Arrange - // Assert - Assert.NotNull(writer); - Assert.IsType(writer); - } + // Act + using var writer = serializeOnlyChangedValues.HasValue + ? _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, serializeOnlyChangedValues.Value) + : _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType); - [Fact] - public void GetSerializationWriterSerializedChangedTrue_RetunsEmptyJson() - { - // Arrange - var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; - testUser.BackingStore.InitializationCompleted = true; - using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); + // Assert + Assert.NotNull(writer); + Assert.IsType(writer); + } - // Act - writer.WriteObjectValue(null, testUser); - using var stream = writer.GetSerializedContent(); - var serializedContent = GetStringFromStream(stream); + [Fact] + public void GetSerializationWriterSerializedChangedTrue_RetunsEmptyJson() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); - // Assert - Assert.NotNull(serializedContent); - Assert.Equal("{}", serializedContent); - } + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); - [Fact] - public void GetSerializationWriterSerializedChangedTrue_ChangedName_ReturnsJustName() - { - // Arrange - var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; - testUser.BackingStore.InitializationCompleted = true; - testUser.Name = "Stephan"; - using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{}", serializedContent); + } - // Act - writer.WriteObjectValue(null, testUser); - using var stream = writer.GetSerializedContent(); - var serializedContent = GetStringFromStream(stream); + [Fact] + public void GetSerializationWriterSerializedChangedTrue_ChangedName_ReturnsJustName() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + testUser.Name = "Stephan"; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, true); - // Assert - Assert.NotNull(serializedContent); - Assert.Equal("{\"name\":\"Stephan\"}", serializedContent); - } + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); - [Fact] - public void GetSerializationWriterSerializedChangedFalse_SerializesEntireObject() - { - // Arrange - var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; - testUser.BackingStore.InitializationCompleted = true; - using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, false); + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{\"name\":\"Stephan\"}", serializedContent); + } - // Act - writer.WriteObjectValue(null, testUser); - using var stream = writer.GetSerializedContent(); - var serializedContent = GetStringFromStream(stream); + [Fact] + public void GetSerializationWriterSerializedChangedFalse_SerializesEntireObject() + { + // Arrange + var testUser = new BackedTestEntity { Id = "1", Name = "testUser" }; + testUser.BackingStore.InitializationCompleted = true; + using var writer = _serializationWriterFactoryRegistry.GetSerializationWriter(_jsonContentType, false); - // Assert - Assert.NotNull(serializedContent); - Assert.Equal("{\"id\":\"1\",\"name\":\"testUser\"}", serializedContent); - } + // Act + writer.WriteObjectValue(null, testUser); + using var stream = writer.GetSerializedContent(); + var serializedContent = GetStringFromStream(stream); - private static string GetStringFromStream(Stream stream) - { - using var reader = new StreamReader(stream); - return reader.ReadToEnd(); + // Assert + Assert.NotNull(serializedContent); + Assert.Equal("{\"id\":\"1\",\"name\":\"testUser\"}", serializedContent); + } + + private static string GetStringFromStream(Stream stream) + { + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } } - } } diff --git a/tests/serialization/json/Mocks/BackedTestEntity.cs b/tests/serialization/json/Mocks/BackedTestEntity.cs index 6ff41b8b..ef627b1a 100644 --- a/tests/serialization/json/Mocks/BackedTestEntity.cs +++ b/tests/serialization/json/Mocks/BackedTestEntity.cs @@ -5,36 +5,36 @@ namespace Microsoft.Kiota.Serialization.Json.Tests.Mocks { - public class BackedTestEntity : IParsable, IBackedModel - { - public BackedTestEntity() + public class BackedTestEntity : IParsable, IBackedModel { - BackingStore = new InMemoryBackingStore(); - } + public BackedTestEntity() + { + BackingStore = new InMemoryBackingStore(); + } - public IBackingStore BackingStore { get; private set; } + public IBackingStore BackingStore { get; private set; } - public string Id - { - get { return BackingStore?.Get("id"); } - set { BackingStore?.Set("id", value); } - } - public string Name - { - get { return BackingStore?.Get("name"); } - set { BackingStore?.Set("name", value); } - } + public string Id + { + get { return BackingStore?.Get("id"); } + set { BackingStore?.Set("id", value); } + } + public string Name + { + get { return BackingStore?.Get("name"); } + set { BackingStore?.Set("name", value); } + } - public IDictionary> GetFieldDeserializers() => - new Dictionary> { + public IDictionary> GetFieldDeserializers() => + new Dictionary> { { "id", n => { Id = n.GetStringValue(); } }, { "name", n => { Name = n.GetStringValue(); } }, - }; - public void Serialize(ISerializationWriter writer) - { - _ = writer ?? throw new ArgumentNullException(nameof(writer)); - writer.WriteStringValue("id", Id); - writer.WriteStringValue("name", Name); + }; + public void Serialize(ISerializationWriter writer) + { + _ = writer ?? throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("name", Name); + } } - } } From a4a03d81e24d3c419792b383ba0db13484832fcb Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Mon, 19 Aug 2024 20:36:02 +0200 Subject: [PATCH 09/11] Removing extensions --- .../KiotaJsonSerializer.Serialization.cs | 12 +-- src/serialization/form/IParsableExtensions.cs | 78 ------------------- src/serialization/json/IParsableExtensions.cs | 78 ------------------- 3 files changed, 2 insertions(+), 166 deletions(-) delete mode 100644 src/serialization/form/IParsableExtensions.cs delete mode 100644 src/serialization/json/IParsableExtensions.cs diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs index 2916d20e..dba6a24d 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Serialization.cs @@ -23,8 +23,6 @@ public static partial class KiotaJsonSerializer /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a stream. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] - [EditorBrowsable(EditorBrowsableState.Never)] public static Stream SerializeAsStream(T value) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value); @@ -34,7 +32,7 @@ public static Stream SerializeAsStream(T value) where T : IParsable /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [Obsolete("This method is obsolete, use SerializeAsStringAsync instead")] [EditorBrowsable(EditorBrowsableState.Never)] public static string SerializeAsString(T value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); @@ -46,8 +44,6 @@ public static string SerializeAsString(T value) where T : IParsable /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] - [EditorBrowsable(EditorBrowsableState.Never)] public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); @@ -57,8 +53,6 @@ public static Task SerializeAsStringAsync(T value, CancellationToken /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a stream. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] - [EditorBrowsable(EditorBrowsableState.Never)] public static Stream SerializeAsStream(IEnumerable value) where T : IParsable => KiotaSerializer.SerializeAsStream(_jsonContentType, value); @@ -68,7 +62,7 @@ public static Stream SerializeAsStream(IEnumerable value) where T : IParsa /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] + [Obsolete("This method is obsolete, use SerializeAsStringAsync instead")] [EditorBrowsable(EditorBrowsableState.Never)] public static string SerializeAsString(IEnumerable value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); @@ -79,8 +73,6 @@ public static string SerializeAsString(IEnumerable value) where T : IParsa /// The object to serialize. /// The token to monitor for cancellation requests. /// The serialized representation as a string. - [Obsolete("This method is obsolete, use the extension methods in Microsoft.Kiota.Serialization.Json.IParsableExtensions instead")] - [EditorBrowsable(EditorBrowsableState.Never)] public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken) where T : IParsable => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, true, cancellationToken); } diff --git a/src/serialization/form/IParsableExtensions.cs b/src/serialization/form/IParsableExtensions.cs deleted file mode 100644 index f95eaf8c..00000000 --- a/src/serialization/form/IParsableExtensions.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Kiota.Abstractions.Serialization; - -namespace Microsoft.Kiota.Serialization.Form; - -/// -/// Serialization extensions for IParsable objects (form url encoded) -/// -public static class IParsableExtensions -{ - private const string _formContentType = "application/x-www-form-urlencoded"; - /// - /// Serializes the given object into stream with form url encoded content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsFormStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a form url encoded string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsFormAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); - - /// - /// Serializes the given object into stream with form url encoded content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsFormStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a form url encoded string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsFormAsync(this IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); - - /// - /// Serializes the given object into stream with form url encoded content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsFormStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_formContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a form url encoded string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsFormAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_formContentType, value, serializeOnlyChangedValues, cancellationToken); - -} \ No newline at end of file diff --git a/src/serialization/json/IParsableExtensions.cs b/src/serialization/json/IParsableExtensions.cs deleted file mode 100644 index 710fa2e5..00000000 --- a/src/serialization/json/IParsableExtensions.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Kiota.Abstractions.Serialization; - -namespace Microsoft.Kiota.Serialization.Json; - -/// -/// Serialization extensions for IParsable objects (JSON) -/// -public static class IParsableExtensions -{ - private const string _jsonContentType = "application/json"; - /// - /// Serializes the given object into stream with json content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsJsonStream(this T value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a json string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsJsonAsync(this T value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - - /// - /// Serializes the given object into stream with json content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsJsonStream(this IEnumerable value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a json string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsJsonAsync(this IEnumerable value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - - /// - /// Serializes the given object into stream with json content type. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The serialized representation as a stream. - public static Stream SerializeAsJsonStream(this T[] value, bool serializeOnlyChangedValues = true) where T : IParsable - => KiotaSerializer.SerializeAsStream(_jsonContentType, value, serializeOnlyChangedValues); - - /// - /// Serializes the given object into a json string. - /// - /// Type of the object to serialize - /// The object to serialize. - /// By default, a backing store is used, and you'll only get changed properties - /// The token to monitor for cancellation requests. - /// The serialized representation as a string. - public static Task SerializeAsJsonAsync(this T[] value, bool serializeOnlyChangedValues = true, CancellationToken cancellationToken = default) where T : IParsable - => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, serializeOnlyChangedValues, cancellationToken); - -} \ No newline at end of file From 8e544fed5420aa185028a34f796856b6e2928c48 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:06:02 +0200 Subject: [PATCH 10/11] Change to nullable in test --- tests/serialization/json/Mocks/BackedTestEntity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/serialization/json/Mocks/BackedTestEntity.cs b/tests/serialization/json/Mocks/BackedTestEntity.cs index ef627b1a..bd5cbeaa 100644 --- a/tests/serialization/json/Mocks/BackedTestEntity.cs +++ b/tests/serialization/json/Mocks/BackedTestEntity.cs @@ -14,12 +14,12 @@ public BackedTestEntity() public IBackingStore BackingStore { get; private set; } - public string Id + public string? Id { get { return BackingStore?.Get("id"); } set { BackingStore?.Set("id", value); } } - public string Name + public string? Name { get { return BackingStore?.Get("name"); } set { BackingStore?.Set("name", value); } From e229345f906996c52fc907479b450a291577f0b7 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Tue, 20 Aug 2024 16:25:22 +0300 Subject: [PATCH 11/11] bumps version and release notes. --- CHANGELOG.md | 6 ++++++ Directory.Build.props | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5435b6f..e2ec3a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.12.0] - 2024-08-20 + +### Changed + +- Improved serialization helper methods to take boolean parameter to override the BackingStore functionality. [#310](https://github.com/microsoft/kiota-dotnet/issues/310) + ## [1.11.3] - 2024-08-16 ### Changed diff --git a/Directory.Build.props b/Directory.Build.props index 5b9bcc79..cd688d28 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.11.3 + 1.12.0 false