Files
decePubClient/Helpers/UnregisteredJson.cs
T

48 lines
1.9 KiB
C#
Raw Normal View History

using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using decePubClient.Models.Mastodon;
using PrivaPub.ClientModels;
namespace decePubClient.Helpers
{
public sealed class UnregisteredJson : IJsonTypeInfoResolver
{
public static readonly UnregisteredJson Instance = new();
static readonly DefaultJsonTypeInfoResolver Reflection = new();
static readonly ConcurrentDictionary<Type, byte> Reported = new();
public static bool Strict { get; set; }
public JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
if (Strict)
throw new NotSupportedException($"{type.FullName} is not registered in a JsonSerializerContext (HR0306).");
if (Reported.TryAdd(type, 0))
Console.Error.WriteLine($"{type.FullName} is serialized without a JsonSerializerContext registration (HR0306)");
return Reflection.GetTypeInfo(type, options);
}
public static void Check(bool strict)
{
Strict = strict;
if (!strict)
return;
var missing = Missing(ClientModelsJsonContext.Default, typeof(WebResult), "PrivaPub.ClientModels")
.Concat(Missing(MastodonJsonContext.Default, typeof(Status), "decePubClient.Models.Mastodon"))
.ToList();
if (missing.Count > 0)
throw new InvalidOperationException("Not registered in a JsonSerializerContext (HR0306): " + string.Join(", ", missing));
}
static IEnumerable<string> Missing(IJsonTypeInfoResolver context, Type anchor, string space) =>
anchor.Assembly.GetTypes()
.Where(t => t.IsClass && t.IsPublic && !t.IsAbstract && !t.IsGenericTypeDefinition && t.Namespace is { } ns && ns.StartsWith(space, StringComparison.Ordinal)
&& !ns.EndsWith(".Resources", StringComparison.Ordinal) && !typeof(Attribute).IsAssignableFrom(t) && !typeof(JsonSerializerContext).IsAssignableFrom(t))
.Where(t => context.GetTypeInfo(t, new JsonSerializerOptions()) == null)
.Select(t => t.FullName);
}
}