< Summary

Information
Class: Elsa.Workflows.Serialization.Converters.ActivityJsonConverter
Assembly: Elsa.Workflows.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs
Line coverage
93%
Covered lines: 54
Uncovered lines: 4
Coverable lines: 58
Total lines: 125
Line coverage: 93.1%
Branch coverage
76%
Covered branches: 23
Total branches: 30
Branch coverage: 76.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Read(...)62.5%8886.95%
Write(...)66.66%66100%
GetActivityDetails(...)87.5%161694.11%
GetClonedOptions(...)100%11100%
GetClonedWriterOptions(...)100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs

#LineLine coverage
 1using System.Text.Json;
 2using System.Text.Json.Serialization;
 3using Elsa.Expressions.Contracts;
 4using Elsa.Extensions;
 5using Elsa.Workflows.Activities;
 6using Elsa.Workflows.Helpers;
 7using Elsa.Workflows.Models;
 8using Elsa.Workflows.Serialization.Helpers;
 9using Microsoft.Extensions.DependencyInjection;
 10
 11namespace Elsa.Workflows.Serialization.Converters;
 12
 13/// <summary>
 14/// (De)serializes objects of type <see cref="IActivity"/>.
 15/// </summary>
 234616public class ActivityJsonConverter(
 234617    IActivityRegistry activityRegistry,
 234618    IExpressionDescriptorRegistry expressionDescriptorRegistry,
 234619    ActivityWriter activityWriter,
 234620    IServiceProvider serviceProvider)
 21    : JsonConverter<IActivity>
 22{
 23    /// <inheritdoc />
 24    public override IActivity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
 25    {
 254626        if (!JsonDocument.TryParseValue(ref reader, out var doc))
 027            throw new JsonException("Failed to parse JsonDocument");
 28
 254629        var activityRoot = doc.RootElement;
 254630        var activityTypeName = GetActivityDetails(activityRoot, out var activityTypeVersion, out var activityDescriptor)
 254631        var notFoundActivityTypeName = ActivityTypeNameHelper.GenerateTypeName<NotFoundActivity>();
 32
 33        // If the activity type is a NotFoundActivity, try to extract the original activity type name and version.
 254634        if (activityTypeName.Equals(notFoundActivityTypeName) && activityRoot.TryGetProperty("originalActivityJson", out
 35        {
 036            activityRoot = JsonDocument.Parse(originalActivityJson.GetString()!).RootElement;
 037            activityTypeName = GetActivityDetails(activityRoot, out activityTypeVersion, out activityDescriptor);
 38        }
 39
 254640        var clonedOptions = GetClonedOptions(options);
 41
 42        // If the activity type is not found, create a NotFoundActivity instead.
 254643        if (activityDescriptor == null)
 44        {
 745            var notFoundActivityDescriptor = activityRegistry.Find<NotFoundActivity>()!;
 746            var notFoundActivity = JsonActivityConstructorContextHelper.CreateActivity<NotFoundActivity>(notFoundActivit
 47
 748            notFoundActivity.Type = notFoundActivityTypeName;
 749            notFoundActivity.Version = 1;
 750            notFoundActivity.MissingTypeName = activityTypeName;
 751            notFoundActivity.MissingTypeVersion = activityTypeVersion;
 752            notFoundActivity.OriginalActivityJson = activityRoot.ToString();
 753            notFoundActivity.SetDisplayText($"Not Found: {activityTypeName}");
 754            notFoundActivity.SetDescription($"Could not find activity type {activityTypeName} with version {activityType
 755            return notFoundActivity;
 56        }
 57
 253958        var context = JsonActivityConstructorContextHelper.Create(activityDescriptor, activityRoot, clonedOptions);
 253959        var activity = activityDescriptor.Constructor(context);
 253960        return activity;
 61    }
 62
 63    /// <inheritdoc />
 64    public override void Write(Utf8JsonWriter writer, IActivity value, JsonSerializerOptions options)
 65    {
 129466        var clonedOptions = GetClonedWriterOptions(options);
 129467        var activityDescriptor = activityRegistry.Find(value.Type, value.Version);
 68
 69        // Give the activity descriptor a chance to customize the serializer options.
 129470        clonedOptions = activityDescriptor?.ConfigureSerializerOptions?.Invoke(clonedOptions) ?? clonedOptions;
 71
 129472        activityWriter.WriteActivity(writer, value, clonedOptions);
 129473    }
 74
 75    private string GetActivityDetails(JsonElement activityRoot, out int activityTypeVersion, out ActivityDescriptor? act
 76    {
 254677        if (!activityRoot.TryGetProperty("type", out var activityTypeNameElement))
 078            throw new JsonException("Failed to extract activity type property");
 79
 254680        var activityTypeName = activityTypeNameElement.GetString()!;
 254681        activityDescriptor = null;
 254682        activityTypeVersion = 0;
 83
 84        // First try and find the activity by its workflow definition version id. This is a special case when working wi
 254685        if (activityRoot.TryGetProperty("workflowDefinitionVersionId", out var workflowDefinitionVersionIdElement))
 86        {
 51187            var workflowDefinitionVersionId = workflowDefinitionVersionIdElement.GetString();
 51188            activityDescriptor = activityRegistry.Find(x =>
 1286189                x.CustomProperties.TryGetValue("WorkflowDefinitionVersionId", out var value) && (string?)value == workfl
 51190            activityTypeVersion = activityDescriptor?.Version ?? 0;
 91        }
 92
 93        // If the activity type version is specified, use that to find the activity descriptor.
 254694        if (activityDescriptor == null && activityRoot.TryGetProperty("version", out var activityVersionElement))
 95        {
 205796            activityTypeVersion = activityVersionElement.GetInt32();
 205797            activityDescriptor = activityRegistry.Find(activityTypeName, activityTypeVersion);
 98        }
 99
 100        // If the activity type version is not specified, use the latest version of the activity descriptor.
 2546101        if (activityDescriptor == null)
 102        {
 7103            activityDescriptor = activityRegistry.Find(activityTypeName);
 7104            activityTypeVersion = activityDescriptor?.Version ?? 0;
 105        }
 106
 2546107        return activityTypeName;
 108    }
 109
 110    private JsonSerializerOptions GetClonedOptions(JsonSerializerOptions options)
 111    {
 3840112        var clonedOptions = new JsonSerializerOptions(options);
 3840113        clonedOptions.Converters.Add(new InputJsonConverterFactory(serviceProvider));
 3840114        clonedOptions.Converters.Add(new OutputJsonConverterFactory(serviceProvider));
 3840115        clonedOptions.Converters.Add(new ExpressionJsonConverterFactory(expressionDescriptorRegistry));
 3840116        return clonedOptions;
 117    }
 118
 119    private JsonSerializerOptions GetClonedWriterOptions(JsonSerializerOptions options)
 120    {
 1294121        var clonedOptions = GetClonedOptions(options);
 1294122        clonedOptions.Converters.Add(new JsonIgnoreCompositeRootConverterFactory(serviceProvider.GetRequiredService<Acti
 1294123        return clonedOptions;
 124    }
 125}