diff --git a/CHANGELOG.md b/CHANGELOG.md index 8baecb2..affef7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Improvements ### MLEM.Data Improvements - **Moved extension methods into matching namespaces to avoid unexpected suggestions** +- Allow static json converters to throw an exception if a key does not exist Removals - **Removed obsolete types DynamicEnumConverter, CopyExtensions, DynamicEnum, NetBufferSerializer, and NetExtensions** diff --git a/MLEM.Data/Json/StaticJsonConverter.cs b/MLEM.Data/Json/StaticJsonConverter.cs index e0cecd9..851328f 100644 --- a/MLEM.Data/Json/StaticJsonConverter.cs +++ b/MLEM.Data/Json/StaticJsonConverter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Newtonsoft.Json; @@ -18,14 +17,17 @@ namespace MLEM.Data.Json { private readonly Dictionary entries; private readonly Dictionary inverse; + private readonly bool throwOnRead; /// /// Creates a new static json converter using the given underlying . /// /// The dictionary to use - public StaticJsonConverter(Dictionary entries) { + /// Whether to throw a in if a key is missing, or throw a if a stored json value is not a string. If this is , returns instead. + public StaticJsonConverter(Dictionary entries, bool throwOnRead = false) { this.entries = entries; - this.inverse = entries.ToDictionary(kv => kv.Value, kv => kv.Key); + this.inverse = StaticJsonConverter.CreateInverse(entries); + this.throwOnRead = throwOnRead; } /// @@ -39,6 +41,18 @@ namespace MLEM.Data.Json { #endif Type type, string memberName) : this(StaticJsonConverter.GetEntries(type, memberName)) {} + /// + /// Creates a new static json converter by finding the underlying from the given type and member name + /// + /// The type that the dictionary is declared in + /// The name of the dictionary itself + /// Whether to throw a in if a key is missing, or throw a if a stored json value is not a string. If this is , returns instead. + public StaticJsonConverter( +#if NET6_0_OR_GREATER + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] +#endif + Type type, string memberName, bool throwOnRead) : this(StaticJsonConverter.GetEntries(type, memberName), throwOnRead) {} + /// Writes the JSON representation of the object. /// The to write to. /// The value. @@ -57,10 +71,15 @@ namespace MLEM.Data.Json { /// The calling serializer. /// The object value. public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) { - var val = reader.Value?.ToString(); - if (val == null) + if (reader.Value == null) return default; - this.entries.TryGetValue(val, out var ret); + if (reader.TokenType != JsonToken.String) { + if (this.throwOnRead) + throw new JsonSerializationException($"Expected a string value for {reader.Value}, got a {reader.TokenType}"); + return default; + } + if (!this.entries.TryGetValue((string) reader.Value, out var ret) && this.throwOnRead) + throw new KeyNotFoundException($"Could not find registered entry for {reader.Value}"); return ret; } @@ -76,5 +95,15 @@ namespace MLEM.Data.Json { return value as Dictionary ?? throw new InvalidCastException($"{value} is not of expected type {typeof(T)}"); } + private static Dictionary CreateInverse(Dictionary entries) { + var ret = new Dictionary(); + foreach (var entry in entries) { + if (ret.ContainsKey(entry.Value)) + throw new ArgumentException($"Cannot create a static json converter with duplicate value {entry.Value}"); + ret.Add(entry.Value, entry.Key); + } + return ret; + } + } }