using System.Buffers; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; namespace Cepis; /// /// Reads any scalar as a string, and a JSON null as the empty string. /// /// /// The API documents every text field as a string and an absent one as /// "", never null. This converter makes a client that meets a /// null, or a code sent as a number, degrade to the documented shape /// instead of throwing: none of those is worth failing a whole lookup over. /// internal sealed class LenientStringConverter : JsonConverter { public override bool HandleNull => true; public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { case JsonTokenType.String: return reader.GetString() ?? ""; case JsonTokenType.Null: return ""; case JsonTokenType.True: return "true"; case JsonTokenType.False: return "false"; case JsonTokenType.Number: var raw = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan.ToArray(); return Encoding.UTF8.GetString(raw); default: throw new JsonException($"expected a string, got {reader.TokenType}"); } } public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { ArgumentNullException.ThrowIfNull(writer); writer.WriteStringValue(value); } public override string ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString() ?? ""; public override void WriteAsPropertyName(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { ArgumentNullException.ThrowIfNull(writer); writer.WritePropertyName(value); } }