< 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>
 232216public class ActivityJsonConverter(
 232217    IActivityRegistry activityRegistry,
 232218    IExpressionDescriptorRegistry expressionDescriptorRegistry,
 232219    ActivityWriter activityWriter,
 232220    IServiceProvider serviceProvider)
 21    : JsonConverter<IActivity>
 22{
 23    /// <inheritdoc />
 24    public override IActivity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
 25    {
 260226        if (!JsonDocument.TryParseValue(ref reader, out var doc))
 027            throw new JsonException("Failed to parse JsonDocument");
 28
 260229        var activityRoot = doc.RootElement;
 260230        var activityTypeName = GetActivityDetails(activityRoot, out var activityTypeVersion, out var activityDescriptor)
 260231        var notFoundActivityTypeName = ActivityTypeNameHelper.GenerateTypeName<NotFoundActivity>();
 32
 33        // If the activity type is a NotFoundActivity, try to extract the original activity type name and version.
 260234        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
 260240        var clonedOptions = GetClonedOptions(options);
 41
 42        // If the activity type is not found, create a NotFoundActivity instead.
 260243        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
 259558        var context = JsonActivityConstructorContextHelper.Create(activityDescriptor, activityRoot, clonedOptions);
 259559        var activity = activityDescriptor.Constructor(context);
 259560        return activity;
 61    }
 62
 63    /// <inheritdoc />
 64    public override void Write(Utf8JsonWriter writer, IActivity value, JsonSerializerOptions options)
 65    {
 115066        var clonedOptions = GetClonedWriterOptions(options);
 115067        var activityDescriptor = activityRegistry.Find(value.Type, value.Version);
 68
 69        // Give the activity descriptor a chance to customize the serializer options.
 115070        clonedOptions = activityDescriptor?.ConfigureSerializerOptions?.Invoke(clonedOptions) ?? clonedOptions;
 71
 115072        activityWriter.WriteActivity(writer, value, clonedOptions);
 115073    }
 74
 75    private string GetActivityDetails(JsonElement activityRoot, out int activityTypeVersion, out ActivityDescriptor? act
 76    {
 260277        if (!activityRoot.TryGetProperty("type", out var activityTypeNameElement))
 078            throw new JsonException("Failed to extract activity type property");
 79
 260280        var activityTypeName = activityTypeNameElement.GetString()!;
 260281        activityDescriptor = null;
 260282        activityTypeVersion = 0;
 83
 84        // First try and find the activity by its workflow definition version id. This is a special case when working wi
 260285        if (activityRoot.TryGetProperty("workflowDefinitionVersionId", out var workflowDefinitionVersionIdElement))
 86        {
 52787            var workflowDefinitionVersionId = workflowDefinitionVersionIdElement.GetString();
 52788            activityDescriptor = activityRegistry.Find(x =>
 1462989                x.CustomProperties.TryGetValue("WorkflowDefinitionVersionId", out var value) && (string?)value == workfl
 52790            activityTypeVersion = activityDescriptor?.Version ?? 0;
 91        }
 92
 93        // If the activity type version is specified, use that to find the activity descriptor.
 260294        if (activityDescriptor == null && activityRoot.TryGetProperty("version", out var activityVersionElement))
 95        {
 209796            activityTypeVersion = activityVersionElement.GetInt32();
 209797            activityDescriptor = activityRegistry.Find(activityTypeName, activityTypeVersion);
 98        }
 99
 100        // If the activity type version is not specified, use the latest version of the activity descriptor.
 2602101        if (activityDescriptor == null)
 102        {
 7103            activityDescriptor = activityRegistry.Find(activityTypeName);
 7104            activityTypeVersion = activityDescriptor?.Version ?? 0;
 105        }
 106
 2602107        return activityTypeName;
 108    }
 109
 110    private JsonSerializerOptions GetClonedOptions(JsonSerializerOptions options)
 111    {
 3752112        var clonedOptions = new JsonSerializerOptions(options);
 3752113        clonedOptions.Converters.Add(new InputJsonConverterFactory(serviceProvider));
 3752114        clonedOptions.Converters.Add(new OutputJsonConverterFactory(serviceProvider));
 3752115        clonedOptions.Converters.Add(new ExpressionJsonConverterFactory(expressionDescriptorRegistry));
 3752116        return clonedOptions;
 117    }
 118
 119    private JsonSerializerOptions GetClonedWriterOptions(JsonSerializerOptions options)
 120    {
 1150121        var clonedOptions = GetClonedOptions(options);
 1150122        clonedOptions.Converters.Add(new JsonIgnoreCompositeRootConverterFactory(serviceProvider.GetRequiredService<Acti
 1150123        return clonedOptions;
 124    }
 125}