Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v14: Refactor and enhance System.Text.Json converters #15960

Merged
merged 14 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
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
Expand Up @@ -32,7 +32,7 @@ public void Configure(JsonOptions options)
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.Converters.Add(new JsonUdiConverter());
options.JsonSerializerOptions.Converters.Add(new JsonGuidUdiConverter());
options.JsonSerializerOptions.Converters.Add(new JsonUdiRangeConverter());
options.JsonSerializerOptions.Converters.Add(new JsonObjectConverter());

options.JsonSerializerOptions.TypeInfoResolver = _umbracoJsonTypeInfoResolver;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace Umbraco.Cms.Core.Serialization;

/// <summary>
/// Provides functionality to serialize objects or value types to JSON and to deserialize JSON into objects or value types, used for data type configuration.
/// </summary>
public interface IConfigurationEditorJsonSerializer : IJsonSerializer
{
}
{ }
19 changes: 19 additions & 0 deletions src/Umbraco.Core/Serialization/IJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
namespace Umbraco.Cms.Core.Serialization;

/// <summary>
/// Provides functionality to serialize objects or value types to JSON and to deserialize JSON into objects or value types.
/// </summary>
public interface IJsonSerializer
{
/// <summary>
/// Converts the specified <paramref name="input" /> into a JSON string.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>
/// A JSON string representation of the value.
/// </returns>
string Serialize(object? input);


/// <summary>
/// Parses the text representing a single JSON value into an instance of the type specified by a generic type parameter.
/// </summary>
/// <typeparam name="T">The target type of the JSON value.</typeparam>
/// <param name="input">The JSON input to parse.</param>
/// <returns>
/// A <typeparamref name="T" /> representation of the JSON value.
/// </returns>
T? Deserialize<T>(string input);
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

36 changes: 0 additions & 36 deletions src/Umbraco.Infrastructure/Serialization/JsonBoolConverter.cs

This file was deleted.

62 changes: 62 additions & 0 deletions src/Umbraco.Infrastructure/Serialization/JsonBooleanConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Umbraco.Cms.Infrastructure.Serialization;

/// <summary>
/// Converts a boolean value to or from JSON, always converting a boolean like value (like <c>1</c> or <c>0</c>) to a boolean.
/// </summary>
public sealed class JsonBooleanConverter : JsonConverter<bool>
{
/// <inheritdoc />
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.TokenType switch
{
JsonTokenType.String => ParseString(ref reader),
JsonTokenType.Number => ParseNumber(ref reader),
JsonTokenType.True => true,
JsonTokenType.False => false,
_ => throw new JsonException(),
};

/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
=> writer.WriteBooleanValue(value);

private static bool ParseString(ref Utf8JsonReader reader)
{
var value = reader.GetString();

if (bool.TryParse(value, out var boolValue))
{
return boolValue;
}

if (long.TryParse(value, out var longValue))
{
return Convert.ToBoolean(longValue);
}

if (double.TryParse(value, out double doubleValue))
{
return Convert.ToBoolean(doubleValue);
}

throw new JsonException();
}

private static bool ParseNumber(ref Utf8JsonReader reader)
{
if (reader.TryGetInt64(out long longValue))
{
return Convert.ToBoolean(longValue);
}

if (reader.TryGetDouble(out double doubleValue))
{
return Convert.ToBoolean(doubleValue);
}

throw new JsonException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Text.Json;

namespace Umbraco.Cms.Infrastructure.Serialization;

/// <summary>
/// Converts a dictionary with a string key to or from JSON, using the <see cref="StringComparer.OrdinalIgnoreCase" /> comparer.
/// </summary>
/// <typeparam name="TValue">The type of the dictionary value.</typeparam>
public sealed class JsonDictionaryStringIgnoreCaseConverter<TValue> : ReadOnlyJsonConverter<Dictionary<string, TValue>>
{
/// <inheritdoc />
public override Dictionary<string, TValue>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}

var dictionary = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase);

while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}

// Get key
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}

string propertyName = reader.GetString() ?? throw new JsonException();
ronaldbarendse marked this conversation as resolved.
Show resolved Hide resolved

// Get value
reader.Read();
TValue? value = JsonSerializer.Deserialize<TValue>(ref reader, options);
if (value is not null)
{
dictionary[propertyName] = value;
}
}

throw new JsonException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Text.Json;

namespace Umbraco.Cms.Infrastructure.Serialization;

/// <summary>
/// Converts a dictionary with a string key to or from JSON, using the <see cref="StringComparer.OrdinalIgnoreCase" /> comparer and interning the string key when reading.
/// </summary>
/// <typeparam name="TValue">The type of the dictionary value.</typeparam>
public sealed class JsonDictionaryStringInternIgnoreCaseConverter<TValue> : ReadOnlyJsonConverter<Dictionary<string, TValue>>
ronaldbarendse marked this conversation as resolved.
Show resolved Hide resolved
{
/// <inheritdoc />
public override Dictionary<string, TValue>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}

var dictionary = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase);

while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}

// Get key
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}

string propertyName = reader.GetString() ?? throw new JsonException();

// Get value
reader.Read();
TValue? value = JsonSerializer.Deserialize<TValue>(ref reader, options);
if (value is not null)
{
dictionary[string.Intern(propertyName)] = value;
}
}

throw new JsonException();
}
}
20 changes: 0 additions & 20 deletions src/Umbraco.Infrastructure/Serialization/JsonGuidUdiConverter.cs

This file was deleted.

Loading
Loading