Skip to content

Commit

Permalink
Merge pull request #6350 from elsa-workflows/bug/complex_type_array_s…
Browse files Browse the repository at this point in the history
…erialization

Improve JSON array conversion in ObjectConverter
  • Loading branch information
sfmskywalker authored Jan 29, 2025
2 parents 9437ab3 + 0560d11 commit 5d653b9
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/modules/Elsa.Expressions/Elsa.Expressions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

<ItemGroup>
<ProjectReference Include="..\..\common\Elsa.Features\Elsa.Features.csproj" />
<ProjectReference Include="..\Elsa.Common\Elsa.Common.csproj" />
</ItemGroup>

</Project>
28 changes: 21 additions & 7 deletions src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,29 @@ public static Result TryConvertTo(this object? value, Type targetType, ObjectCon
return jsonElement.Deserialize(targetType, serializerOptions);
}

if (value is JsonNode jsonNode and not JsonArray) // If the value is a JsonNode, we can convert it to the target type. If it's a JsonArray, we let the enumerable conversion logic handle it.
if (value is JsonNode jsonNode)
{
return underlyingTargetType switch
if (jsonNode is not JsonArray jsonArray)
{
{ } t when t == typeof(string) => jsonNode.ToString(),
{ } t when t == typeof(ExpandoObject) && jsonNode.GetValueKind() == JsonValueKind.Object => JsonSerializer.Deserialize<ExpandoObject>(jsonNode.ToJsonString()),
{ } t when t != typeof(object) || converterOptions?.DeserializeJsonObjectToObject == true => jsonNode.Deserialize(targetType, serializerOptions),
_ => jsonNode
};
return underlyingTargetType switch
{
{ } t when t == typeof(string) => jsonNode.ToString(),
{ } t when t == typeof(ExpandoObject) && jsonNode.GetValueKind() == JsonValueKind.Object => JsonSerializer.Deserialize<ExpandoObject>(jsonNode.ToJsonString()),
{ } t when t != typeof(object) || converterOptions?.DeserializeJsonObjectToObject == true => jsonNode.Deserialize(targetType, serializerOptions),
_ => jsonNode
};
}

// Convert to target type if target type is an array or a generic collection.
if (targetType.IsArray || targetType.IsCollectionType())
{
// The element type of the source array is JsonObject. If the element type of the target array is Object then return the source array as an array of JsonObjects.
// Deserializing normally would return an array of JsonElement instead of JsonObject, but we want to keep JsonObject elements:
var targetElementType = targetType.IsArray ? targetType.GetElementType()! : targetType.GenericTypeArguments[0];

if (targetElementType != typeof(object))
return jsonArray.Deserialize(targetType, serializerOptions);
}
}

if (underlyingSourceType == typeof(string) && !underlyingTargetType.IsPrimitive && underlyingTargetType != typeof(object))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Elsa.Workflows.Core.UnitTests.ObjectConversion
{
public class Person
{
public double? Age { get; set; }

public string? Name { get; set; }
}
}
17 changes: 17 additions & 0 deletions test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,21 @@ public void ConvertTo_JsonArrayToICollectionOfObject_ReturnsCollectionOfJsonObje
Assert.Equal("Bob", secondElement["name"]?.ToString());
Assert.Equal("25", secondElement["age"]?.ToString());
}

[Fact]
public void ConvertFrom_JsonArrayToArrayOfComplextType_ReturnsArrayOfComplexType()
{
// Arrange
var jsonArrayString = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";
var options = new ObjectConverterOptions();

// Act
var result = jsonArrayString.ConvertTo<Person[]>(options);

// Assert
Assert.NotNull(result);
Assert.Equal(2, result.Length);
Assert.Equal("Alice", result[0].Name);
Assert.Equal("Bob", result[1].Name);
}
}

0 comments on commit 5d653b9

Please sign in to comment.