Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json;

Check notice on line 1 in src/Umbraco.Infrastructure/Serialization/JsonBlockValueConverter.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 5.13 to 4.38, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
using System.Text.Json.Serialization;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Extensions;
Expand Down Expand Up @@ -121,7 +121,17 @@
}

private List<BlockItemData> DeserializeBlockItemData(ref Utf8JsonReader reader, JsonSerializerOptions options, Type typeToConvert, string propertyName)
=> DeserializeListOf<BlockItemData>(ref reader, options, typeToConvert, propertyName);
{
try
{
return DeserializeListOf<BlockItemData>(ref reader, options, typeToConvert, propertyName);
}
catch (JsonException ex) when (ex.Path?.EndsWith(".values") is true)
{
// If we hit a JsonException due to the "values" property conflict, attempt the fallback deserialization
return FallbackBlockItemDataDeserialization(ref reader, options, typeToConvert, propertyName);
}
}

private List<BlockItemVariation> DeserializeBlockVariation(ref Utf8JsonReader reader, JsonSerializerOptions options, Type typeToConvert, string propertyName)
=> DeserializeListOf<BlockItemVariation>(ref reader, options, typeToConvert, propertyName);
Expand Down Expand Up @@ -224,5 +234,86 @@
}
}
}
}

[Obsolete("Only needed to support the old data schema. Remove in V18.")]
private static List<BlockItemData> FallbackBlockItemDataDeserialization(ref Utf8JsonReader reader, JsonSerializerOptions options, Type typeToConvert, string propertyName)
{
JsonElement arrayElement = JsonSerializer.Deserialize<JsonElement>(ref reader, options);
if (arrayElement.ValueKind != JsonValueKind.Array)
{
throw new JsonException($"Expected array for {propertyName} from type: {typeToConvert.FullName}.");
}

return arrayElement
.EnumerateArray()
.Select(itemElement => DeserializeBlockItemElement(itemElement, options))
.OfType<BlockItemData>()
.ToList();
}

[Obsolete("Only needed to support the old data schema. Remove in V18.")]
private static BlockItemData? DeserializeBlockItemElement(JsonElement itemElement, JsonSerializerOptions options)
{
try
{
BlockItemData? blockItem = JsonSerializer.Deserialize<BlockItemData>(itemElement.GetRawText(), options);
if (blockItem is null)
{
return null;
}

// Ensure the 'values' collection is initialized. This can happen if the JSON contained a conflicting null 'values' property.
blockItem.Values ??= [];
return blockItem;
}
catch (JsonException ex) when (ex.Path?.EndsWith(".values") == true && itemElement.TryGetProperty("values", out _))
{
// Only attempt renaming if we're confident this is a "values" property conflict
return DeserializeWithRenamedValues(itemElement, options);
}
}

[Obsolete("Only needed to support the old data schema. Remove in V18.")]
private static BlockItemData? DeserializeWithRenamedValues(JsonElement itemElement, JsonSerializerOptions options)
{
var tempPropertyName = $"_values_{Guid.NewGuid():N}";
var modifiedJson = CreateModifiedJsonWithRenamedValues(itemElement, tempPropertyName, options);
BlockItemData? blockItemData = JsonSerializer.Deserialize<BlockItemData>(modifiedJson, options);

if (blockItemData != null)
{
RestoreOriginalValuesPropertyName(blockItemData, tempPropertyName);
}

return blockItemData;
}

[Obsolete("Only needed to support the old data schema. Remove in V18.")]
private static string CreateModifiedJsonWithRenamedValues(JsonElement element, string tempPropertyName, JsonSerializerOptions options)
{
var jsonObject = new Dictionary<string, object?>();
foreach (JsonProperty property in element.EnumerateObject())
{
if (property.Name.Equals("values", StringComparison.OrdinalIgnoreCase))
{
// Rename the conflicting property to avoid deserialization conflict
jsonObject[tempPropertyName] = property.Value;
continue;
}

jsonObject[property.Name] = property.Value;
}

return JsonSerializer.Serialize(jsonObject, options);
}

[Obsolete("Only needed to support the old data schema. Remove in V18.")]
private static void RestoreOriginalValuesPropertyName(BlockItemData blockItemData, string tempPropertyName)
{
if (blockItemData.RawPropertyValues.Remove(tempPropertyName, out var valuesData))
{
// Move the temporarily renamed property back to "values" in RawPropertyValues
blockItemData.RawPropertyValues["values"] = valuesData;
}
}
}