using System; using System.Text.Json; using System.Text.Json.Serialization; namespace GB5Shared.JsonConverter { // Clients (e.g. legacy GB4-style criteria payloads) send enum values as // quoted numeric strings ("2") or plain member names ("Equal"), not just // the bare integer System.Text.Json expects by default. This converter // accepts all three forms for any enum type. public class FlexibleEnumConverter : JsonConverter where T : struct, Enum { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { case JsonTokenType.Number: return (T)Enum.ToObject(typeof(T), reader.GetInt32()); case JsonTokenType.String: var raw = reader.GetString(); if (string.IsNullOrWhiteSpace(raw)) return default; if (int.TryParse(raw, out var numeric)) return (T)Enum.ToObject(typeof(T), numeric); return Enum.TryParse(raw, ignoreCase: true, out var parsed) ? parsed : throw new JsonException($"Unable to convert \"{raw}\" to enum {typeof(T)}."); default: throw new JsonException($"Unexpected token {reader.TokenType} when parsing enum {typeof(T)}."); } } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); } } // Non-generic factory so it can be registered once in JsonSerializerOptions.Converters // and apply to every enum type encountered, rather than listing each enum by hand. public class FlexibleEnumConverterFactory : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum; public override System.Text.Json.Serialization.JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var converterType = typeof(FlexibleEnumConverter<>).MakeGenericType(typeToConvert); return (System.Text.Json.Serialization.JsonConverter)Activator.CreateInstance(converterType)!; } } }