From 96644834d8b0c6bc2c6501e897ad9ba65bae99a7 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Fri, 5 Apr 2024 21:24:25 +0200 Subject: [PATCH] Improve object deserialization in PolymorphicObjectConverter This commit enhances the deserialization of objects within the PolymorphicObjectConverter. It includes updates to handle collections and derived classes from Collection or List, modifications to the invocation of the addSetMethod, and simplification of the list reading process within the StartArray case. The changes result in a more robust and efficient deserialization process for complex object structures. --- .../Converters/PolymorphicObjectConverter.cs | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs index 0cc00867a..2efd594d0 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs @@ -101,8 +101,16 @@ public class PolymorphicObjectConverter : JsonConverter return parsedModel.Deserialize(targetType, newOptions)!; } + var isCollection = typeof(ICollection).IsAssignableFrom(targetType); + // Otherwise, deserialize the object as an array. - var elementType = targetType.IsArray ? targetType.GetElementType() : targetType.GenericTypeArguments.FirstOrDefault() ?? typeof(object); + var elementType = targetType.IsArray + ? targetType.GetElementType() + : targetType.GenericTypeArguments.FirstOrDefault() ?? + (isCollection // Could be a class derived from Collection or List. + ? targetType.BaseType?.GenericTypeArguments[0] + : targetType.GenericTypeArguments.FirstOrDefault() + ?? typeof(object)); if (elementType == null) throw new InvalidOperationException($"Cannot determine the element type of array '{targetType}'."); @@ -124,7 +132,7 @@ public class PolymorphicObjectConverter : JsonConverter referenceResolver?.AddReference(id, collection); var isHashSet = targetType.GenericTypeArguments.Length == 1 && typeof(ISet<>).MakeGenericType(targetType.GenericTypeArguments[0]).IsAssignableFrom(targetType); - var addSetMethod = targetType.GetMethod("Add", new[] { elementType })!; + var addSetMethod = targetType.GetMethod("Add", [elementType])!; foreach (var element in values) { @@ -135,7 +143,10 @@ public class PolymorphicObjectConverter : JsonConverter } else if (isHashSet) { - addSetMethod.Invoke(collection, new[] { deserializedElement }); + addSetMethod.Invoke(collection, new[] + { + deserializedElement + }); } else if (collection is IList list) { @@ -308,23 +319,23 @@ public class PolymorphicObjectConverter : JsonConverter switch (reader.TokenType) { case JsonTokenType.StartArray: - { - var list = new List(); - while (reader.Read()) { - switch (reader.TokenType) + var list = new List(); + while (reader.Read()) { - default: - list.Add(Read(ref reader, typeof(object), options)); - break; + switch (reader.TokenType) + { + default: + list.Add(Read(ref reader, typeof(object), options)); + break; - case JsonTokenType.EndArray: - return list; + case JsonTokenType.EndArray: + return list; + } } - } - throw new JsonException(); - } + throw new JsonException(); + } case JsonTokenType.StartObject: var dict = new ExpandoObject() as IDictionary; var referenceResolver = (CustomPreserveReferenceResolver)(options.ReferenceHandler as CrossScopedReferenceHandler)?.GetResolver()!; @@ -350,7 +361,7 @@ public class PolymorphicObjectConverter : JsonConverter else if (key == IdPropertyName) { var referenceId = reader.GetString()!; - + // Attempt to add the reference; if not found, we can ignore it and assume that the user is using the $id property for something else, such as in JSON $schema. referenceResolver.TryAddReference(referenceId, dict); }