V14: Migrate Newtonsoft to System.Text in value converters (#15728)

* Force system text json for IJSonSerializer

* Migrate ColorPickerValueConverter

* Move ColorPickerValueConverter

* Clean up ColorPickerValueConverter

* Remove obsoleted property editors

* Migrate FlexibleDropdownPropertyValueConverter to System.Text.Json

* Use IJsonSerializer instead and move the value converter to Core

* Migrate ImageCropperValueConverter to System.Text.Json

* Inject jsonserializer in test and obsolete old constructor

* Migrate JsonValueConverter to System.Text.Json

* Remove ContextualConfigurationEditorJsonSerializer

* Remove JsonNetSerializer

* Remove obsolete DeserializeSubset from JsonSerializer interface

* Fix FlexibleDropdownPropertyValueConverter

* Update test JSON to be actual valid json

* Update more test json

* Update time format to be valid

* Add JsonPropertyName to models
This commit is contained in:
Mole
2024-02-22 11:22:57 +01:00
committed by GitHub
parent 58bc868374
commit 7735552877
45 changed files with 117 additions and 361 deletions

View File

@@ -1,42 +0,0 @@
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Serialization;
namespace Umbraco.Cms.Infrastructure.Serialization;
public class ConfigurationEditorJsonSerializer : JsonNetSerializer, IConfigurationEditorJsonSerializer
{
public ConfigurationEditorJsonSerializer()
{
Settings.Converters.Add(new FuzzyBooleanConverter());
Settings.ContractResolver = new ConfigurationCustomContractResolver();
}
private class ConfigurationCustomContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
// base.CreateProperty deals with [JsonProperty("name")]
JsonProperty property = base.CreateProperty(member, memberSerialization);
// override with our custom attribute, if any
ConfigurationFieldAttribute? attribute = member.GetCustomAttribute<ConfigurationFieldAttribute>();
if (attribute != null)
{
property.PropertyName = attribute.Key;
}
// for value types,
// don't try to deserialize nulls (in legacy json)
// no impact on serialization (value cannot be null)
if (member is PropertyInfo propertyInfo && propertyInfo.PropertyType.IsValueType)
{
property.NullValueHandling = NullValueHandling.Ignore;
}
return property;
}
}
}

View File

@@ -1,47 +0,0 @@
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Web;
namespace Umbraco.Cms.Infrastructure.Serialization;
public class ContextualConfigurationEditorJsonSerializer : IConfigurationEditorJsonSerializer
{
private readonly IRequestAccessor _requestAccessor;
private readonly ConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;
private readonly SystemTextConfigurationEditorJsonSerializer _systemTextConfigurationEditorJsonSerializer;
public ContextualConfigurationEditorJsonSerializer(IRequestAccessor requestAccessor)
{
_requestAccessor = requestAccessor;
_configurationEditorJsonSerializer = new ConfigurationEditorJsonSerializer();
_systemTextConfigurationEditorJsonSerializer = new SystemTextConfigurationEditorJsonSerializer();
}
public string Serialize(object? input) => ContextualizedSerializer().Serialize(input);
public T? Deserialize<T>(string input) => ContextualizedSerializer().Deserialize<T>(input);
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
private IConfigurationEditorJsonSerializer ContextualizedSerializer()
{
try
{
var requestedPath = _requestAccessor.GetRequestUrl()?.AbsolutePath;
if (requestedPath != null)
{
// add white listed paths for the System.Text.Json config serializer here
// - always use it for the new management API
if (requestedPath.Contains("/umbraco/management/api/"))
{
return _systemTextConfigurationEditorJsonSerializer;
}
}
}
catch (Exception ex)
{
// ignore - this whole thing is a temporary workaround, let's not make a fuss
}
return _configurationEditorJsonSerializer;
}
}

View File

@@ -1,50 +0,0 @@
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Web;
namespace Umbraco.Cms.Infrastructure.Serialization;
// FIXME: move away from Json.NET; this is a temporary fix that attempts to use System.Text.Json for management API operations, Json.NET for other operations
public class ContextualJsonSerializer : IJsonSerializer
{
private readonly IRequestAccessor _requestAccessor;
private readonly IJsonSerializer _jsonNetSerializer;
private readonly IJsonSerializer _systemTextSerializer;
public ContextualJsonSerializer(IRequestAccessor requestAccessor)
{
_requestAccessor = requestAccessor;
_jsonNetSerializer = new JsonNetSerializer();
_systemTextSerializer = new SystemTextJsonSerializer();
}
public string Serialize(object? input) => ContextualizedSerializer().Serialize(input);
public T? Deserialize<T>(string input) => ContextualizedSerializer().Deserialize<T>(input);
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
private IJsonSerializer ContextualizedSerializer()
{
try
{
var requestedPath = _requestAccessor.GetRequestUrl()?.AbsolutePath;
if (requestedPath != null)
{
// add white listed paths for the System.Text.Json config serializer here
// - always use it for the new management API
if (requestedPath.Contains("/umbraco/management/api/"))
{
return _systemTextSerializer;
}
}
}
catch (Exception ex)
{
// ignore - this whole thing is a temporary workaround, let's not make a fuss
}
return _jsonNetSerializer;
}
}

View File

@@ -1,35 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Umbraco.Cms.Core.Serialization;
namespace Umbraco.Cms.Infrastructure.Serialization;
public class JsonNetSerializer : IJsonSerializer
{
protected JsonSerializerSettings Settings { get; } = new()
{
Converters = new List<JsonConverter> { new StringEnumConverter() },
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
};
public string Serialize(object? input) => JsonConvert.SerializeObject(input, Settings);
public T? Deserialize<T>(string input) => JsonConvert.DeserializeObject<T>(input, Settings);
public T? DeserializeSubset<T>(string input, string key)
{
ArgumentNullException.ThrowIfNull(key);
JObject? root = Deserialize<JObject>(input);
JToken? jToken = root?.SelectToken(key);
return jToken switch
{
JArray jArray => jArray.ToObject<T>(),
JObject jObject => jObject.ToObject<T>(),
_ => jToken is null ? default : jToken.Value<T>(),
};
}
}

View File

@@ -33,6 +33,4 @@ public class SystemTextConfigurationEditorJsonSerializer : IConfigurationEditorJ
public string Serialize(object? input) => JsonSerializer.Serialize(input, _jsonSerializerOptions);
public T? Deserialize<T>(string input) => JsonSerializer.Deserialize<T>(input, _jsonSerializerOptions);
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
}

View File

@@ -21,6 +21,4 @@ public class SystemTextJsonSerializer : IJsonSerializer
public string Serialize(object? input) => JsonSerializer.Serialize(input, _jsonSerializerOptions);
public T? Deserialize<T>(string input) => JsonSerializer.Deserialize<T>(input, _jsonSerializerOptions);
public T? DeserializeSubset<T>(string input, string key) => throw new NotSupportedException();
}