Migrations: Adjust the JsonBlockValueConverter to handle conflicts with 'values' property (#20429)
* Adjust the `JsonBlockValueConverter` to handle conflicts with 'values' property (due to old data schema) * Simplify code * Add unit test to verify change. --------- Co-authored-by: Andy Butland <abutland73@gmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Extensions;
|
||||
@@ -121,7 +122,17 @@ public class JsonBlockValueConverter : JsonConverter<BlockValue>
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private List<BlockItemVariation> DeserializeBlockVariation(ref Utf8JsonReader reader, JsonSerializerOptions options, Type typeToConvert, string propertyName)
|
||||
=> DeserializeListOf<BlockItemVariation>(ref reader, options, typeToConvert, propertyName);
|
||||
@@ -224,5 +235,38 @@ public class JsonBlockValueConverter : JsonConverter<BlockValue>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Only needed to support the old data schema. Remove in V18.")]
|
||||
private static List<BlockItemData> FallbackBlockItemDataDeserialization(ref Utf8JsonReader reader, JsonSerializerOptions options)
|
||||
{
|
||||
JsonArray? arrayElement = JsonSerializer.Deserialize<JsonArray>(ref reader, options);
|
||||
|
||||
return arrayElement?
|
||||
.Select(itemElement => DeserializeBlockItemData(itemElement, options))
|
||||
.OfType<BlockItemData>()
|
||||
.ToList() ?? [];
|
||||
}
|
||||
|
||||
[Obsolete("Only needed to support the old data schema. Remove in V18.")]
|
||||
private static BlockItemData? DeserializeBlockItemData(JsonNode? jsonNode, JsonSerializerOptions options)
|
||||
{
|
||||
if (jsonNode is not JsonObject jsonObject || jsonObject.ContainsKey("values") is false)
|
||||
{
|
||||
// Nothing to be done, just deserialize as usual
|
||||
return jsonNode.Deserialize<BlockItemData>(options);
|
||||
}
|
||||
|
||||
// Handle the "values" property conflict by extracting the "values" property first and adding it to the
|
||||
// RawPropertyValues dictionary after deserialization
|
||||
JsonNode? values = jsonObject["values"];
|
||||
jsonObject.Remove("values");
|
||||
|
||||
BlockItemData? blockItemData = jsonObject.Deserialize<BlockItemData>(options);
|
||||
if (blockItemData is not null)
|
||||
{
|
||||
blockItemData.RawPropertyValues["values"] = values.Deserialize<object?>(options);
|
||||
}
|
||||
|
||||
return blockItemData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,4 +470,42 @@ public class JsonBlockValueConverterTests
|
||||
var serializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
Assert.DoesNotThrow(() => serializer.Deserialize<BlockListValue>(json));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case that verifies the fix for https://github.com/umbraco/Umbraco-CMS/issues/20409.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Can_Deserialize_BlockGrid_With_Blocks_Using_Values_As_Property_Alias()
|
||||
{
|
||||
// Create a serialized BlockGridValue in Umbraco 13 format that has a block with a property alias "values".
|
||||
var serialized = @"{
|
||||
""layout"":{
|
||||
""Umbraco.BlockList"":[
|
||||
{
|
||||
""contentUdi"":""umb://element/6ad18441631140d48515ea0fc5b00425""
|
||||
}
|
||||
]
|
||||
},
|
||||
""contentData"":[
|
||||
{
|
||||
""contentTypeKey"":""a1d1123c-289b-4a05-b33f-9f06cb723da1"",
|
||||
""udi"":""umb://element/6ad18441631140d48515ea0fc5b00425"",
|
||||
""text"":""Text"",
|
||||
""values"":""Values""
|
||||
}
|
||||
],
|
||||
""settingsData"":[
|
||||
]
|
||||
}";
|
||||
|
||||
var serializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
|
||||
var deserialized = serializer.Deserialize<BlockGridValue>(serialized);
|
||||
|
||||
Assert.IsNotNull(deserialized);
|
||||
|
||||
Assert.AreEqual(1, deserialized.ContentData.Count);
|
||||
Assert.AreEqual(2, deserialized.ContentData[0].RawPropertyValues.Count);
|
||||
Assert.AreEqual("Text", deserialized.ContentData[0].RawPropertyValues["text"]);
|
||||
Assert.AreEqual("Values", deserialized.ContentData[0].RawPropertyValues["values"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user