From 7fd13809c3fda8e405bebe8f4817f42e2379c36d Mon Sep 17 00:00:00 2001 From: Andreas Jakof Date: Fri, 11 Oct 2024 11:26:43 +0200 Subject: [PATCH 01/13] Added Non-Generic Solution to KiotaDeserialization --- ...aJsonSerializer.Deserialization.Untyped.cs | 88 ++++++++++++++++++ .../KiotaSerializer.Deserializtion.Untyped.cs | 93 +++++++++++++++++++ .../DeserializationHelpersTests.cs | 68 ++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs create mode 100644 src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs new file mode 100644 index 0000000..98a5ad5 --- /dev/null +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs @@ -0,0 +1,88 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + + +#if NET5_0_OR_GREATER + +using System.Threading.Tasks; +using System.Threading; +using System.IO; +using System; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +#pragma warning disable IL3050 + +namespace Microsoft.Kiota.Abstractions.Serialization; + +public static partial class KiotaJsonSerializer +{ + private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; + private abstract class KiotaJsonDeserializer + { + private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); + + public static KiotaJsonDeserializer Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); + + private static KiotaJsonDeserializer CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) + => (KiotaJsonDeserializer)Activator.CreateInstance(typeof(TypedKiotaJsonDeserializer<>).MakeGenericType(targetType))!; + + + internal abstract Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default); + internal abstract Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default); + internal abstract Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default); + internal abstract Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default); + + private class TypedKiotaJsonDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : KiotaJsonDeserializer where T : IParsable + { + internal override async Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(stream, cancellationToken); + internal override async Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(serializedRepresentation, cancellationToken); + internal override async Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(stream, cancellationToken)).OfType(); + internal override async Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(serializedRepresentation, cancellationToken)).OfType(); + } + } + + /// + /// Deserializes the given string into an object. + /// + /// The target type to deserialize + /// The serialized representation of the object. + /// The cancellation token for the task + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaJsonDeserializer.Create(type).DeserializeAsync(serializedRepresentation, cancellationToken); + + /// + /// Deserializes the given stream into an object. + /// + /// The target type to deserialize + /// The stream to deserialize. + /// The cancellation token for the task + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, Stream stream, CancellationToken cancellationToken = default) + => KiotaJsonDeserializer.Create(type).DeserializeAsync(stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The stream to deserialize. + /// The cancellation token for the task + public static Task> DeserializeCollectionAsync(Type type, Stream stream, CancellationToken cancellationToken = default) + => KiotaJsonDeserializer.Create(type).DeserializeCollectionAsync(stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The serialized representation of the object. + /// The cancellation token for the task + public static Task> DeserializeCollectionAsync(Type type, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaJsonDeserializer.Create(type).DeserializeCollectionAsync(serializedRepresentation, cancellationToken); + + +} + +#pragma warning restore IL3050 +#endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs new file mode 100644 index 0000000..62f4f32 --- /dev/null +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs @@ -0,0 +1,93 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + + +#if NET5_0_OR_GREATER + +using System.Threading.Tasks; +using System.Threading; +using System.IO; +using System; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +#pragma warning disable IL3050 + +namespace Microsoft.Kiota.Abstractions.Serialization; + +public static partial class KiotaSerializer +{ + private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; + private abstract class KiotaDeserializer + { + private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); + + public static KiotaDeserializer Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); + + private static KiotaDeserializer CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) + => (KiotaDeserializer)Activator.CreateInstance(typeof(TypedKiotaDeserializer<>).MakeGenericType(targetType))!; + + + internal abstract Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + internal abstract Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + internal abstract Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + internal abstract Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + + private class TypedKiotaDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : KiotaDeserializer where T : IParsable + { + internal override async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); + internal override async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); + internal override async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); + internal override async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); + } + } + + /// + /// Deserializes the given string into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The serialized representation of the object. + /// The cancellation token for the task + /// + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaDeserializer.Create(type).DeserializeAsync(contentType, serializedRepresentation, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The stream to deserialize. + /// The cancellation token for the task + /// + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) + => KiotaDeserializer.Create(type).DeserializeAsync(contentType, stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The stream to deserialize. + /// The cancellation token for the task + public static Task> DeserializeCollectionAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) + => KiotaDeserializer.Create(type).DeserializeCollectionAsync(contentType, stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The serialized representation of the object. + /// The cancellation token for the task + public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaDeserializer.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); + +} + +#pragma warning restore IL3050 +#endif \ No newline at end of file diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.cs index 0cc79e4..7f0cd66 100644 --- a/tests/abstractions/Serialization/DeserializationHelpersTests.cs +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.cs @@ -171,4 +171,72 @@ public async Task DeserializesCollectionOfObjectAsync() Assert.NotNull(result); Assert.Single(result); } + +#if NET5_0_OR_GREATER + [Fact] + public async Task DeserializesObjectUntypedWithoutReflectionAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() + { + Id = "123" + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = (TestEntity?) await KiotaSerializer.DeserializeAsync(typeof(TestEntity), _jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Equal("123", result.Id); + } + + [Fact] + public async Task DeserializesObjectUntypedWithReflectionAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() + { + Id = "123" + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = (TestEntity?) await KiotaSerializer.DeserializeAsync(typeof(TestEntity),_jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Equal("123", result.Id); + } + + [Fact] + public async Task DeserializesCollectionOfObjectUntypedAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetCollectionOfObjectValues(It.IsAny>())).Returns(new List { + new TestEntity() + { + Id = "123" + } + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = await KiotaSerializer.DeserializeCollectionAsync(typeof(TestEntity), _jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Single(result); + var first = result.First() as TestEntity; + Assert.NotNull(first); + Assert.Equal("123", first.Id); + } +#endif + } From 7a4129a61e9ac80a815f693f6a8331d006e2fca6 Mon Sep 17 00:00:00 2001 From: Andreas Jakof Date: Mon, 14 Oct 2024 15:40:42 +0200 Subject: [PATCH 02/13] Comments of PR #953 --- Microsoft.Kiota.lutconfig | 6 + ...onSerializer.Deserialization.NonGeneric.cs | 98 +++++++++++++++++ ...aJsonSerializer.Deserialization.Untyped.cs | 88 --------------- ...otaSerializer.Deserializtion.NonGeneric.cs | 103 ++++++++++++++++++ .../KiotaSerializer.Deserializtion.Untyped.cs | 93 ---------------- .../DeserializationHelpersTests.NonGeneric.cs | 77 +++++++++++++ .../DeserializationHelpersTests.cs | 70 +----------- 7 files changed, 285 insertions(+), 250 deletions(-) create mode 100644 Microsoft.Kiota.lutconfig create mode 100644 src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs delete mode 100644 src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs create mode 100644 src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs delete mode 100644 src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs create mode 100644 tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs diff --git a/Microsoft.Kiota.lutconfig b/Microsoft.Kiota.lutconfig new file mode 100644 index 0000000..596a860 --- /dev/null +++ b/Microsoft.Kiota.lutconfig @@ -0,0 +1,6 @@ + + + true + true + 180000 + \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs new file mode 100644 index 0000000..8bf99e9 --- /dev/null +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -0,0 +1,98 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.\ +// ------------------------------------------------------------------------------ + +#if NET8_0_OR_GREATER + +using System.Threading.Tasks; +using System.Threading; +using System.IO; +using System; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Kiota.Abstractions.Serialization; + +public static partial class KiotaJsonSerializer +{ + private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; + + private static class KiotaJsonDeserializationWrapperFactory + { + private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static IKiotaJsonDeserializationWrapper Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + private static IKiotaJsonDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) + { + if(Activator.CreateInstance(typeof(KiotaJsonDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaJsonDeserializationWrapper deserializer) + return deserializer; + else + throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); + } + } + + private interface IKiotaJsonDeserializationWrapper + { + Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default); + Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default); + + } + + private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaJsonDeserializationWrapper where T : IParsable + { + public async Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(stream, cancellationToken); + public async Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(serializedRepresentation, cancellationToken); + public async Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(stream, cancellationToken)).OfType(); + public async Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(serializedRepresentation, cancellationToken)).OfType(); + } + + /// + /// Deserializes the given string into an object. + /// + /// The target type to deserialize + /// The serialized representation of the object. + /// The cancellation token for the task + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeAsync(serializedRepresentation, cancellationToken); + + /// + /// Deserializes the given stream into an object. + /// + /// The target type to deserialize + /// The stream to deserialize. + /// The cancellation token for the task + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, Stream stream, CancellationToken cancellationToken = default) + => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeAsync(stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The stream to deserialize. + /// The cancellation token for the task + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task> DeserializeCollectionAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) + => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The serialized representation of the object. + /// The cancellation token for the task + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task> DeserializeCollectionAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(serializedRepresentation, cancellationToken); + + +} +#endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs deleted file mode 100644 index 98a5ad5..0000000 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.Untyped.cs +++ /dev/null @@ -1,88 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - - -#if NET5_0_OR_GREATER - -using System.Threading.Tasks; -using System.Threading; -using System.IO; -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; - -#pragma warning disable IL3050 - -namespace Microsoft.Kiota.Abstractions.Serialization; - -public static partial class KiotaJsonSerializer -{ - private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; - private abstract class KiotaJsonDeserializer - { - private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); - - public static KiotaJsonDeserializer Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); - - private static KiotaJsonDeserializer CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) - => (KiotaJsonDeserializer)Activator.CreateInstance(typeof(TypedKiotaJsonDeserializer<>).MakeGenericType(targetType))!; - - - internal abstract Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default); - internal abstract Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default); - internal abstract Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default); - internal abstract Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default); - - private class TypedKiotaJsonDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : KiotaJsonDeserializer where T : IParsable - { - internal override async Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(stream, cancellationToken); - internal override async Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(serializedRepresentation, cancellationToken); - internal override async Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(stream, cancellationToken)).OfType(); - internal override async Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(serializedRepresentation, cancellationToken)).OfType(); - } - } - - /// - /// Deserializes the given string into an object. - /// - /// The target type to deserialize - /// The serialized representation of the object. - /// The cancellation token for the task - public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaJsonDeserializer.Create(type).DeserializeAsync(serializedRepresentation, cancellationToken); - - /// - /// Deserializes the given stream into an object. - /// - /// The target type to deserialize - /// The stream to deserialize. - /// The cancellation token for the task - public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, Stream stream, CancellationToken cancellationToken = default) - => KiotaJsonDeserializer.Create(type).DeserializeAsync(stream, cancellationToken); - - /// - /// Deserializes the given stream into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The stream to deserialize. - /// The cancellation token for the task - public static Task> DeserializeCollectionAsync(Type type, Stream stream, CancellationToken cancellationToken = default) - => KiotaJsonDeserializer.Create(type).DeserializeCollectionAsync(stream, cancellationToken); - - /// - /// Deserializes the given stream into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The serialized representation of the object. - /// The cancellation token for the task - public static Task> DeserializeCollectionAsync(Type type, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaJsonDeserializer.Create(type).DeserializeCollectionAsync(serializedRepresentation, cancellationToken); - - -} - -#pragma warning restore IL3050 -#endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs new file mode 100644 index 0000000..e78eac4 --- /dev/null +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs @@ -0,0 +1,103 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +#if NET8_0_OR_GREATER + +using System.Threading.Tasks; +using System.Threading; +using System.IO; +using System; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Kiota.Abstractions.Serialization; + +public static partial class KiotaSerializer +{ + private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; + + private static class KiotaDeserializationWrapperFactory + { + private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static IKiotaDeserializationWrapper Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) + { + if(Activator.CreateInstance(typeof(TypedKiotaDeserializer<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) + return deserializer; + else + throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); + } + } + private interface IKiotaDeserializationWrapper + { + Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + + } + private class TypedKiotaDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable + { + public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); + public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); + public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); + public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); + } + + /// + /// Deserializes the given string into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The serialized representation of the object. + /// The cancellation token for the task + /// + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaDeserializationWrapperFactory.Create(type).DeserializeAsync(contentType, serializedRepresentation, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The stream to deserialize. + /// The cancellation token for the task + /// + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) + => KiotaDeserializationWrapperFactory.Create(type).DeserializeAsync(contentType, stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The stream to deserialize. + /// The cancellation token for the task + + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task> DeserializeCollectionAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) + => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, stream, cancellationToken); + + /// + /// Deserializes the given stream into a collection of objects based on the content type. + /// + /// The target type to deserialize + /// The content type of the stream. + /// The serialized representation of the object. + /// The cancellation token for the task + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) + => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); + +} +#endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs deleted file mode 100644 index 62f4f32..0000000 --- a/src/abstractions/serialization/KiotaSerializer.Deserializtion.Untyped.cs +++ /dev/null @@ -1,93 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - - -#if NET5_0_OR_GREATER - -using System.Threading.Tasks; -using System.Threading; -using System.IO; -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; - -#pragma warning disable IL3050 - -namespace Microsoft.Kiota.Abstractions.Serialization; - -public static partial class KiotaSerializer -{ - private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; - private abstract class KiotaDeserializer - { - private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); - - public static KiotaDeserializer Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); - - private static KiotaDeserializer CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) - => (KiotaDeserializer)Activator.CreateInstance(typeof(TypedKiotaDeserializer<>).MakeGenericType(targetType))!; - - - internal abstract Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - internal abstract Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - internal abstract Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - internal abstract Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - - private class TypedKiotaDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : KiotaDeserializer where T : IParsable - { - internal override async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); - internal override async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); - internal override async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); - internal override async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); - } - } - - /// - /// Deserializes the given string into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The content type of the stream. - /// The serialized representation of the object. - /// The cancellation token for the task - /// - public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaDeserializer.Create(type).DeserializeAsync(contentType, serializedRepresentation, cancellationToken); - - /// - /// Deserializes the given stream into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The content type of the stream. - /// The stream to deserialize. - /// The cancellation token for the task - /// - public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) - => KiotaDeserializer.Create(type).DeserializeAsync(contentType, stream, cancellationToken); - - /// - /// Deserializes the given stream into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The content type of the stream. - /// The stream to deserialize. - /// The cancellation token for the task - public static Task> DeserializeCollectionAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) - => KiotaDeserializer.Create(type).DeserializeCollectionAsync(contentType, stream, cancellationToken); - - /// - /// Deserializes the given stream into a collection of objects based on the content type. - /// - /// The target type to deserialize - /// The content type of the stream. - /// The serialized representation of the object. - /// The cancellation token for the task - public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaDeserializer.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); - -} - -#pragma warning restore IL3050 -#endif \ No newline at end of file diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs new file mode 100644 index 0000000..d9b42a3 --- /dev/null +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs @@ -0,0 +1,77 @@ +#if NET8_0_OR_GREATER +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Tests.Mocks; +using Moq; +using Xunit; + +namespace Microsoft.Kiota.Abstractions.Tests.Serialization; + +public partial class DeserializationHelpersTests +{ + + [Fact] + public async Task DeserializesObjectUntypedWithoutReflectionAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() + { + Id = "123" + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = (TestEntity?)await KiotaSerializer.DeserializeAsync(typeof(TestEntity), _jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Equal("123", result.Id); + } + + [Fact] + public async Task DeserializesObjectUntypedWithReflectionAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() + { + Id = "123" + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = (TestEntity?)await KiotaSerializer.DeserializeAsync(typeof(TestEntity), _jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Equal("123", result.Id); + } + + [Fact] + public async Task DeserializesCollectionOfObjectUntypedAsync() + { + var strValue = "{'id':'123'}"; + var mockParseNode = new Mock(); + mockParseNode.Setup(x => x.GetCollectionOfObjectValues(It.IsAny>())).Returns(new List { + new TestEntity() + { + Id = "123" + } + }); + var mockJsonParseNodeFactory = new Mock(); + mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); + mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); + ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; + + var result = await KiotaSerializer.DeserializeCollectionAsync(typeof(TestEntity), _jsonContentType, strValue); + + Assert.NotNull(result); + Assert.Single(result); + var first = result.First() as TestEntity; + Assert.NotNull(first); + Assert.Equal("123", first.Id); + } +} +#endif diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.cs index 7f0cd66..e86dd56 100644 --- a/tests/abstractions/Serialization/DeserializationHelpersTests.cs +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.Kiota.Abstractions.Tests.Serialization; -public class DeserializationHelpersTests +public partial class DeserializationHelpersTests { private const string _jsonContentType = "application/json"; [Fact] @@ -171,72 +171,4 @@ public async Task DeserializesCollectionOfObjectAsync() Assert.NotNull(result); Assert.Single(result); } - -#if NET5_0_OR_GREATER - [Fact] - public async Task DeserializesObjectUntypedWithoutReflectionAsync() - { - var strValue = "{'id':'123'}"; - var mockParseNode = new Mock(); - mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() - { - Id = "123" - }); - var mockJsonParseNodeFactory = new Mock(); - mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); - mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); - ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; - - var result = (TestEntity?) await KiotaSerializer.DeserializeAsync(typeof(TestEntity), _jsonContentType, strValue); - - Assert.NotNull(result); - Assert.Equal("123", result.Id); - } - - [Fact] - public async Task DeserializesObjectUntypedWithReflectionAsync() - { - var strValue = "{'id':'123'}"; - var mockParseNode = new Mock(); - mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() - { - Id = "123" - }); - var mockJsonParseNodeFactory = new Mock(); - mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); - mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); - ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; - - var result = (TestEntity?) await KiotaSerializer.DeserializeAsync(typeof(TestEntity),_jsonContentType, strValue); - - Assert.NotNull(result); - Assert.Equal("123", result.Id); - } - - [Fact] - public async Task DeserializesCollectionOfObjectUntypedAsync() - { - var strValue = "{'id':'123'}"; - var mockParseNode = new Mock(); - mockParseNode.Setup(x => x.GetCollectionOfObjectValues(It.IsAny>())).Returns(new List { - new TestEntity() - { - Id = "123" - } - }); - var mockJsonParseNodeFactory = new Mock(); - mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); - mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); - ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; - - var result = await KiotaSerializer.DeserializeCollectionAsync(typeof(TestEntity), _jsonContentType, strValue); - - Assert.NotNull(result); - Assert.Single(result); - var first = result.First() as TestEntity; - Assert.NotNull(first); - Assert.Equal("123", first.Id); - } -#endif - } From 5386905ca204919c127499c34528ca8f2deec894 Mon Sep 17 00:00:00 2001 From: Andreas Jakof Date: Mon, 14 Oct 2024 15:59:59 +0200 Subject: [PATCH 03/13] reenabled the new methods for .NET5 -7 --- ...onSerializer.Deserialization.NonGeneric.cs | 19 +++++++++++++------ ...otaSerializer.Deserializtion.NonGeneric.cs | 19 +++++++++++++++---- .../DeserializationHelpersTests.NonGeneric.cs | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs index 8bf99e9..48cad22 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.\ // ------------------------------------------------------------------------------ -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER using System.Threading.Tasks; using System.Threading; @@ -14,10 +14,20 @@ using System.Linq; namespace Microsoft.Kiota.Abstractions.Serialization; - public static partial class KiotaJsonSerializer { - private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; +#if NET8_0_OR_GREATER +#else + /// + /// Palceholder for .NET < 8 + /// + private class RequiresDynamicCodeAttribute : Attribute + { + public RequiresDynamicCodeAttribute(string _) { } + } + +#endif + private static bool IsIParsable(this Type type) => type.IsAssignableTo(typeof(IParsable)); private static class KiotaJsonDeserializationWrapperFactory { @@ -42,7 +52,6 @@ private interface IKiotaJsonDeserializationWrapper Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default); - } private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaJsonDeserializationWrapper where T : IParsable @@ -92,7 +101,5 @@ public static Task> DeserializeCollectionAsync(Type targe [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] public static Task> DeserializeCollectionAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(serializedRepresentation, cancellationToken); - - } #endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs index e78eac4..1d82e65 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER using System.Threading.Tasks; using System.Threading; @@ -17,7 +17,18 @@ namespace Microsoft.Kiota.Abstractions.Serialization; public static partial class KiotaSerializer { - private static bool IsIParsable(this Type? type) => type?.IsAssignableTo(typeof(IParsable)) ?? false; +#if NET8_0_OR_GREATER +#else + /// + /// Palceholder for .NET < 8 + /// + private class RequiresDynamicCodeAttribute : Attribute + { + public RequiresDynamicCodeAttribute(string _) { } + } + +#endif + private static bool IsIParsable(this Type type) => type.IsAssignableTo(typeof(IParsable)); private static class KiotaDeserializationWrapperFactory { @@ -35,14 +46,15 @@ private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedM throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); } } + private interface IKiotaDeserializationWrapper { Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - } + private class TypedKiotaDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable { public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); @@ -98,6 +110,5 @@ public static Task> DeserializeCollectionAsync(Type type, [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); - } #endif \ No newline at end of file diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs index d9b42a3..1fbcec7 100644 --- a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs @@ -1,4 +1,4 @@ -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions.Tests.Mocks; using Moq; From 57d24a028d4337fc2134782959a78cdd9e59e29c Mon Sep 17 00:00:00 2001 From: Andreas Jakof Date: Mon, 14 Oct 2024 16:29:43 +0200 Subject: [PATCH 04/13] forgot to rename a type/class --- .../KiotaSerializer.Deserializtion.NonGeneric.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs index 1d82e65..7d012cc 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs @@ -40,7 +40,7 @@ private static class KiotaDeserializationWrapperFactory [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) { - if(Activator.CreateInstance(typeof(TypedKiotaDeserializer<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) + if(Activator.CreateInstance(typeof(KiotaDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) return deserializer; else throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); @@ -55,7 +55,7 @@ private interface IKiotaDeserializationWrapper Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); } - private class TypedKiotaDeserializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable + private class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable { public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); From a7f3dbefcf516ba40c896194d5685bf6488f9532 Mon Sep 17 00:00:00 2001 From: Andreas Jakof Date: Tue, 15 Oct 2024 09:13:54 +0200 Subject: [PATCH 05/13] resolved additional comments --- ...onSerializer.Deserialization.NonGeneric.cs | 88 ++++++------------- ...otaSerializer.Deserializtion.NonGeneric.cs | 74 ++++++++++------ .../DeserializationHelpersTests.NonGeneric.cs | 3 +- 3 files changed, 77 insertions(+), 88 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs index 48cad22..dfb313b 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -2,65 +2,20 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.\ // ------------------------------------------------------------------------------ -#if NET5_0_OR_GREATER - using System.Threading.Tasks; using System.Threading; using System.IO; using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; + using System.Collections.Generic; -using System.Linq; + +#if NET5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#endif namespace Microsoft.Kiota.Abstractions.Serialization; public static partial class KiotaJsonSerializer { -#if NET8_0_OR_GREATER -#else - /// - /// Palceholder for .NET < 8 - /// - private class RequiresDynamicCodeAttribute : Attribute - { - public RequiresDynamicCodeAttribute(string _) { } - } - -#endif - private static bool IsIParsable(this Type type) => type.IsAssignableTo(typeof(IParsable)); - - private static class KiotaJsonDeserializationWrapperFactory - { - private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); - - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] - public static IKiotaJsonDeserializationWrapper Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); - - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] - private static IKiotaJsonDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) - { - if(Activator.CreateInstance(typeof(KiotaJsonDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaJsonDeserializationWrapper deserializer) - return deserializer; - else - throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); - } - } - - private interface IKiotaJsonDeserializationWrapper - { - Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default); - Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default); - } - - private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaJsonDeserializationWrapper where T : IParsable - { - public async Task DeserializeAsync(Stream stream, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(stream, cancellationToken); - public async Task DeserializeAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaJsonSerializer.DeserializeAsync(serializedRepresentation, cancellationToken); - public async Task> DeserializeCollectionAsync(Stream stream, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(stream, cancellationToken)).OfType(); - public async Task> DeserializeCollectionAsync(string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaJsonSerializer.DeserializeCollectionAsync(serializedRepresentation, cancellationToken)).OfType(); - } /// /// Deserializes the given string into an object. @@ -68,9 +23,15 @@ private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(Dynami /// The target type to deserialize /// The serialized representation of the object. /// The cancellation token for the task - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif +#if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeAsync(serializedRepresentation, cancellationToken); +#else + public static Task DeserializeAsync(Type targetType, string serializedRepresentation , CancellationToken cancellationToken = default) +#endif + => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeAsync(_jsonContentType, serializedRepresentation, cancellationToken); /// /// Deserializes the given stream into an object. @@ -78,9 +39,15 @@ private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(Dynami /// The target type to deserialize /// The stream to deserialize. /// The cancellation token for the task - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif +#if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, Stream stream, CancellationToken cancellationToken = default) - => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeAsync(stream, cancellationToken); +#else + public static Task DeserializeAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) +#endif + => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeAsync(_jsonContentType, stream, cancellationToken); /// /// Deserializes the given stream into a collection of objects based on the content type. @@ -88,9 +55,11 @@ private class KiotaJsonDeserializationWrapper<[DynamicallyAccessedMembers(Dynami /// The target type to deserialize /// The stream to deserialize. /// The cancellation token for the task - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif public static Task> DeserializeCollectionAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) - => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(stream, cancellationToken); + => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, stream, cancellationToken); /// /// Deserializes the given stream into a collection of objects based on the content type. @@ -98,8 +67,9 @@ public static Task> DeserializeCollectionAsync(Type targe /// The target type to deserialize /// The serialized representation of the object. /// The cancellation token for the task - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif public static Task> DeserializeCollectionAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaJsonDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(serializedRepresentation, cancellationToken); + => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, serializedRepresentation, cancellationToken); } -#endif \ No newline at end of file diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs index 7d012cc..aab0b55 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs @@ -2,43 +2,46 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ -#if NET5_0_OR_GREATER + using System.Threading.Tasks; using System.Threading; using System.IO; using System; using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; + + + +#if NET5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#endif namespace Microsoft.Kiota.Abstractions.Serialization; public static partial class KiotaSerializer { -#if NET8_0_OR_GREATER -#else - /// - /// Palceholder for .NET < 8 - /// - private class RequiresDynamicCodeAttribute : Attribute - { - public RequiresDynamicCodeAttribute(string _) { } - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsIParsable(this Type type) => typeof(IParsable).IsAssignableFrom(type); -#endif - private static bool IsIParsable(this Type type) => type.IsAssignableTo(typeof(IParsable)); - - private static class KiotaDeserializationWrapperFactory + internal static class KiotaDeserializationWrapperFactory { private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); - +#if NET7_0_OR_GREATER [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif public static IKiotaDeserializationWrapper Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); +#if NET7_0_OR_GREATER [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif +#if NET5_0_OR_GREATER private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) +#else + private static IKiotaDeserializationWrapper CreateInternal(Type targetType) +#endif { if(Activator.CreateInstance(typeof(KiotaDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) return deserializer; @@ -47,16 +50,19 @@ private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedM } } - private interface IKiotaDeserializationWrapper + internal interface IKiotaDeserializationWrapper { Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); } - - private class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable - { +#if NET5_0_OR_GREATER + internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable +#else + internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable +#endif +{ public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); @@ -72,8 +78,14 @@ private class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamicall /// The cancellation token for the task /// - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif +#if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) +#else + public static Task DeserializeAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) +#endif => KiotaDeserializationWrapperFactory.Create(type).DeserializeAsync(contentType, serializedRepresentation, cancellationToken); /// @@ -84,8 +96,14 @@ private class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamicall /// The stream to deserialize. /// The cancellation token for the task /// - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif +#if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) +#else + public static Task DeserializeAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) +#endif => KiotaDeserializationWrapperFactory.Create(type).DeserializeAsync(contentType, stream, cancellationToken); /// @@ -95,8 +113,9 @@ private class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamicall /// The content type of the stream. /// The stream to deserialize. /// The cancellation token for the task - - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif public static Task> DeserializeCollectionAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, stream, cancellationToken); @@ -107,8 +126,9 @@ public static Task> DeserializeCollectionAsync(Type type, /// The content type of the stream. /// The serialized representation of the object. /// The cancellation token for the task - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#if NET7_0_OR_GREATER + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] +#endif public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs index 1fbcec7..bab53f0 100644 --- a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs @@ -1,4 +1,4 @@ -#if NET5_0_OR_GREATER + using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions.Tests.Mocks; using Moq; @@ -74,4 +74,3 @@ public async Task DeserializesCollectionOfObjectUntypedAsync() Assert.Equal("123", first.Id); } } -#endif From 62c6b0ed048df5fedda96c2c491a121cb4f08439 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 09:56:30 -0400 Subject: [PATCH 06/13] chore: formatting --- .../KiotaJsonSerializer.Deserialization.NonGeneric.cs | 9 ++++----- .../KiotaSerializer.Deserializtion.NonGeneric.cs | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs index dfb313b..22746cf 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -2,12 +2,11 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.\ // ------------------------------------------------------------------------------ -using System.Threading.Tasks; -using System.Threading; -using System.IO; using System; - using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; @@ -29,7 +28,7 @@ public static partial class KiotaJsonSerializer #if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) #else - public static Task DeserializeAsync(Type targetType, string serializedRepresentation , CancellationToken cancellationToken = default) + public static Task DeserializeAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) #endif => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeAsync(_jsonContentType, serializedRepresentation, cancellationToken); diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs index aab0b55..09e4692 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs @@ -4,14 +4,14 @@ -using System.Threading.Tasks; -using System.Threading; -using System.IO; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; @@ -62,7 +62,7 @@ internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamical #else internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable #endif -{ + { public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); From c5a4d9146d537dd4fc49d1e592740bf6163c86b4 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 09:59:35 -0400 Subject: [PATCH 07/13] fix: typo in file name Signed-off-by: Vincent Biret --- ...onGeneric.cs => KiotaSerializer.Deserialization.NonGeneric.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/abstractions/serialization/{KiotaSerializer.Deserializtion.NonGeneric.cs => KiotaSerializer.Deserialization.NonGeneric.cs} (100%) diff --git a/src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs similarity index 100% rename from src/abstractions/serialization/KiotaSerializer.Deserializtion.NonGeneric.cs rename to src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs From 9f6cff94c0ca908b0f7090817411d0916bece67e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 10:01:38 -0400 Subject: [PATCH 08/13] chore: additional formatting Signed-off-by: Vincent Biret --- .../KiotaJsonSerializer.Deserialization.NonGeneric.cs | 8 ++++---- .../KiotaSerializer.Deserialization.NonGeneric.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs index 22746cf..9442d36 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -23,7 +23,7 @@ public static partial class KiotaJsonSerializer /// The serialized representation of the object. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif #if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) @@ -39,7 +39,7 @@ public static partial class KiotaJsonSerializer /// The stream to deserialize. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif #if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, Stream stream, CancellationToken cancellationToken = default) @@ -55,7 +55,7 @@ public static partial class KiotaJsonSerializer /// The stream to deserialize. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, stream, cancellationToken); @@ -67,7 +67,7 @@ public static Task> DeserializeCollectionAsync(Type targe /// The serialized representation of the object. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, serializedRepresentation, cancellationToken); diff --git a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs index 09e4692..9d5e41c 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs @@ -26,7 +26,7 @@ public static partial class KiotaSerializer [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsIParsable(this Type type) => typeof(IParsable).IsAssignableFrom(type); - internal static class KiotaDeserializationWrapperFactory + static internal class KiotaDeserializationWrapperFactory { private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); #if NET7_0_OR_GREATER @@ -79,7 +79,7 @@ internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper whe /// #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif #if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) @@ -97,7 +97,7 @@ internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper whe /// The cancellation token for the task /// #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif #if NET5_0_OR_GREATER public static Task DeserializeAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) @@ -114,7 +114,7 @@ internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper whe /// The stream to deserialize. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type type, string contentType, Stream stream, CancellationToken cancellationToken = default) => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, stream, cancellationToken); @@ -127,7 +127,7 @@ public static Task> DeserializeCollectionAsync(Type type, /// The serialized representation of the object. /// The cancellation token for the task #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type type, string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => KiotaDeserializationWrapperFactory.Create(type).DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken); From 29a94c0336f84445b41d444b4a3e65be013a39f2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 10:09:56 -0400 Subject: [PATCH 09/13] fix: aligns json methods to simply call into media type methods Signed-off-by: Vincent Biret --- .../KiotaJsonSerializer.Deserialization.NonGeneric.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs index 9442d36..809885d 100644 --- a/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaJsonSerializer.Deserialization.NonGeneric.cs @@ -30,7 +30,7 @@ public static partial class KiotaJsonSerializer #else public static Task DeserializeAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) #endif - => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeAsync(_jsonContentType, serializedRepresentation, cancellationToken); + => KiotaSerializer.DeserializeAsync(targetType, _jsonContentType, serializedRepresentation, cancellationToken); /// /// Deserializes the given stream into an object. @@ -46,7 +46,7 @@ public static partial class KiotaJsonSerializer #else public static Task DeserializeAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) #endif - => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeAsync(_jsonContentType, stream, cancellationToken); + => KiotaSerializer.DeserializeAsync(targetType, _jsonContentType, stream, cancellationToken); /// /// Deserializes the given stream into a collection of objects based on the content type. @@ -58,7 +58,7 @@ public static partial class KiotaJsonSerializer [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type targetType, Stream stream, CancellationToken cancellationToken = default) - => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, stream, cancellationToken); + => KiotaSerializer.DeserializeCollectionAsync(targetType, _jsonContentType, stream, cancellationToken); /// /// Deserializes the given stream into a collection of objects based on the content type. @@ -70,5 +70,5 @@ public static Task> DeserializeCollectionAsync(Type targe [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif public static Task> DeserializeCollectionAsync(Type targetType, string serializedRepresentation, CancellationToken cancellationToken = default) - => KiotaSerializer.KiotaDeserializationWrapperFactory.Create(targetType).DeserializeCollectionAsync(_jsonContentType, serializedRepresentation, cancellationToken); + => KiotaSerializer.DeserializeCollectionAsync(targetType, _jsonContentType, serializedRepresentation, cancellationToken); } From 65092e8a0deef6ba4233377707ae295cdaf2df13 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 10:18:31 -0400 Subject: [PATCH 10/13] chore: moves inner interfaces and classes so it does not falsy flag as shadowing parent methods Signed-off-by: Vincent Biret --- ...taSerializer.Deserialization.NonGeneric.cs | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs index 9d5e41c..f0fb955 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs @@ -21,54 +21,52 @@ namespace Microsoft.Kiota.Abstractions.Serialization; -public static partial class KiotaSerializer +internal interface IKiotaDeserializationWrapper +{ + Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); + Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); +} +#if NET5_0_OR_GREATER +internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable +#else +internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable +#endif +{ + public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); + public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); + public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); + public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); +} +static internal class KiotaDeserializationWrapperFactory { [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsIParsable(this Type type) => typeof(IParsable).IsAssignableFrom(type); - - static internal class KiotaDeserializationWrapperFactory - { - private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); + private static bool IsIParsable(Type type) => typeof(IParsable).IsAssignableFrom(type); + private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif - public static IKiotaDeserializationWrapper Create(Type type) => type.IsIParsable() ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); + static internal IKiotaDeserializationWrapper Create(Type type) => IsIParsable(type) ? _deserializers.GetOrAdd(type, CreateInternal) : throw new ArgumentException("The given Type is not of IParsable", nameof(type)); #if NET7_0_OR_GREATER - [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] -#endif -#if NET5_0_OR_GREATER - private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) -#else - private static IKiotaDeserializationWrapper CreateInternal(Type targetType) + [RequiresDynamicCode("Activator creates an instance of a generic class with the Target Type as the generic type argument.")] #endif - { - if(Activator.CreateInstance(typeof(KiotaDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) - return deserializer; - else - throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); - } - } - - internal interface IKiotaDeserializationWrapper - { - Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - } #if NET5_0_OR_GREATER - internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable + private static IKiotaDeserializationWrapper CreateInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType) #else - internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable + private static IKiotaDeserializationWrapper CreateInternal(Type targetType) #endif { - public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); - public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); - public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); - public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); + if(Activator.CreateInstance(typeof(KiotaDeserializationWrapper<>).MakeGenericType(targetType)) is IKiotaDeserializationWrapper deserializer) + return deserializer; + else + throw new InvalidOperationException($"Unable to create deserializer for type {targetType}"); } +} +public static partial class KiotaSerializer +{ /// /// Deserializes the given string into a collection of objects based on the content type. /// From 56b509f4ac8b5a2592561d3ebd771d66f81bfe4e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 10:24:35 -0400 Subject: [PATCH 11/13] chore: adds missing configure await Signed-off-by: Vincent Biret --- .../KiotaSerializer.Deserialization.NonGeneric.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs index f0fb955..20bc4af 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs @@ -34,10 +34,10 @@ internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamical internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable #endif { - public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken); - public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken); - public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken)).OfType(); - public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken)).OfType(); + public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken).ConfigureAwait(false); + public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false); + public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken).ConfigureAwait(false)).OfType(); + public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false)).OfType(); } static internal class KiotaDeserializationWrapperFactory { From 0411dcacbee419c35f579c5e99f5cbadf0837c08 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 15 Oct 2024 10:25:15 -0400 Subject: [PATCH 12/13] chore: removes optional parameters since types are internal Signed-off-by: Vincent Biret --- ...KiotaSerializer.Deserialization.NonGeneric.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs index 20bc4af..4602f79 100644 --- a/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs +++ b/src/abstractions/serialization/KiotaSerializer.Deserialization.NonGeneric.cs @@ -23,10 +23,10 @@ namespace Microsoft.Kiota.Abstractions.Serialization; internal interface IKiotaDeserializationWrapper { - Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default); - Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default); + Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken); + Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken); + Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken); + Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken); } #if NET5_0_OR_GREATER internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> : IKiotaDeserializationWrapper where T : IParsable @@ -34,10 +34,10 @@ internal class KiotaDeserializationWrapper<[DynamicallyAccessedMembers(Dynamical internal class KiotaDeserializationWrapper : IKiotaDeserializationWrapper where T : IParsable #endif { - public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken).ConfigureAwait(false); - public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false); - public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken).ConfigureAwait(false)).OfType(); - public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken = default) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false)).OfType(); + public async Task DeserializeAsync(string contentType, Stream stream, CancellationToken cancellationToken) => await KiotaSerializer.DeserializeAsync(contentType, stream, cancellationToken).ConfigureAwait(false); + public async Task DeserializeAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken) => await KiotaSerializer.DeserializeAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false); + public async Task> DeserializeCollectionAsync(string contentType, Stream stream, CancellationToken cancellationToken) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, stream, cancellationToken).ConfigureAwait(false)).OfType(); + public async Task> DeserializeCollectionAsync(string contentType, string serializedRepresentation, CancellationToken cancellationToken) => (await KiotaSerializer.DeserializeCollectionAsync(contentType, serializedRepresentation, cancellationToken).ConfigureAwait(false)).OfType(); } static internal class KiotaDeserializationWrapperFactory { From f7e71ddfd36c04f17fb2ba425b958e3b8921dbab Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Mon, 28 Oct 2024 09:56:08 +0300 Subject: [PATCH 13/13] updates version and release notes removes duplicate tests --- CHANGELOG.md | 6 ++++++ Directory.Build.props | 2 +- .../DeserializationHelpersTests.NonGeneric.cs | 20 ------------------- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97f7ede..a52b7fa 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.13.2] - 2024-10-28 + +### Changed + +- Added Non-Generic Solution to KiotaDeserialization helper method. [#436](https://github.com/microsoft/kiota-dotnet/pull/436) + ## [1.13.1] - 2024-10-10 ### Changed diff --git a/Directory.Build.props b/Directory.Build.props index bfec8f6..9988389 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.13.1 + 1.13.2 false diff --git a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs index bab53f0..c2251d8 100644 --- a/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs +++ b/tests/abstractions/Serialization/DeserializationHelpersTests.NonGeneric.cs @@ -29,26 +29,6 @@ public async Task DeserializesObjectUntypedWithoutReflectionAsync() Assert.Equal("123", result.Id); } - [Fact] - public async Task DeserializesObjectUntypedWithReflectionAsync() - { - var strValue = "{'id':'123'}"; - var mockParseNode = new Mock(); - mockParseNode.Setup(x => x.GetObjectValue(It.IsAny>())).Returns(new TestEntity() - { - Id = "123" - }); - var mockJsonParseNodeFactory = new Mock(); - mockJsonParseNodeFactory.Setup(x => x.GetRootParseNodeAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(mockParseNode.Object)); - mockJsonParseNodeFactory.Setup(x => x.ValidContentType).Returns(_jsonContentType); - ParseNodeFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockJsonParseNodeFactory.Object; - - var result = (TestEntity?)await KiotaSerializer.DeserializeAsync(typeof(TestEntity), _jsonContentType, strValue); - - Assert.NotNull(result); - Assert.Equal("123", result.Id); - } - [Fact] public async Task DeserializesCollectionOfObjectUntypedAsync() {