mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.5 KiB
102 lines
3.5 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Squidex.Infrastructure.Json.System;
|
|
|
|
public sealed class StringConverter<T> : JsonConverter<T> where T : notnull
|
|
{
|
|
private readonly Func<string, T> convertFromString;
|
|
private readonly Func<T, string?> convertToString;
|
|
|
|
public StringConverter(Func<string, T> convertFromString, Func<T, string?>? convertToString = null)
|
|
{
|
|
this.convertFromString = convertFromString;
|
|
this.convertToString = convertToString ?? (x => x.ToString());
|
|
}
|
|
|
|
public StringConverter()
|
|
{
|
|
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
|
|
|
|
convertFromString = x => (T)typeConverter.ConvertFromInvariantString(x)!;
|
|
convertToString = x => typeConverter.ConvertToInvariantString(x)!;
|
|
}
|
|
|
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
{
|
|
switch (reader.TokenType)
|
|
{
|
|
case JsonTokenType.String:
|
|
var text = reader.GetString();
|
|
try
|
|
{
|
|
return convertFromString(text!);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ThrowHelper.JsonSystemException("Error while converting from string.", ex);
|
|
return default;
|
|
}
|
|
|
|
case JsonTokenType.StartObject:
|
|
var optionsWithoutSelf = OptionClones.GetOptionsWithoutConverter(options, this);
|
|
|
|
return JsonSerializer.Deserialize<T>(ref reader, optionsWithoutSelf);
|
|
|
|
default:
|
|
ThrowHelper.JsonSystemException($"Expected string or object, got {reader.TokenType}.");
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
{
|
|
return convertFromString(reader.GetString()!);
|
|
}
|
|
|
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
|
{
|
|
writer.WriteStringValue(convertToString(value));
|
|
}
|
|
|
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
|
{
|
|
writer.WritePropertyName(convertToString(value)!);
|
|
}
|
|
}
|
|
|
|
#pragma warning disable MA0048 // File name must match type name
|
|
internal static class OptionClones
|
|
#pragma warning restore MA0048 // File name must match type name
|
|
{
|
|
private static readonly ConditionalWeakTable<JsonSerializerOptions, JsonSerializerOptions> Clones = [];
|
|
|
|
public static JsonSerializerOptions GetOptionsWithoutConverter(JsonSerializerOptions source, JsonConverter converter)
|
|
{
|
|
if (!source.Converters.Contains(converter))
|
|
{
|
|
return source;
|
|
}
|
|
|
|
if (!Clones.TryGetValue(source, out var clone))
|
|
{
|
|
clone = new JsonSerializerOptions(source);
|
|
|
|
// Remove the current converter, otherwise we would create a stackoverflow exception.
|
|
clone.Converters.Remove(converter);
|
|
|
|
Clones.TryAdd(source, clone);
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
}
|
|
|