#region License // The MIT License (MIT) // // Copyright (c) 2020 Wanzyee Studio // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #endregion using System; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.UnityConverters.Helpers; namespace Newtonsoft.Json.UnityConverters { /// /// Custom base Newtonsoft.Json.JsonConverter to filter serialized properties. /// public abstract class PartialConverter : JsonConverter where T : new() { protected abstract void ReadValue(ref T value, string name, JsonReader reader, JsonSerializer serializer); protected abstract void WriteJsonProperties(JsonWriter writer, T value, JsonSerializer serializer); /// /// Determine if the object type is /// /// Type of the object. /// true if this can convert the specified type; otherwise, false. public override bool CanConvert(Type objectType) { return objectType == typeof(T) || (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Nullable<>) && objectType.GenericTypeArguments[0] == typeof(T)); } /// /// Read the specified properties to the object. /// /// The object value. /// The Newtonsoft.Json.JsonReader to read from. /// Type of the object. /// The existing value of object being read. /// The calling serializer. [return: MaybeNull] public override object ReadJson( JsonReader reader, Type objectType, [AllowNull] object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { bool isNullableStruct = objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Nullable<>); return isNullableStruct ? null : (object)default(T); } return InternalReadJson(reader, serializer, existingValue); } [return: MaybeNull] private T InternalReadJson(JsonReader reader, JsonSerializer serializer, [AllowNull] object existingValue) { if (reader.TokenType != JsonToken.StartObject) { throw reader.CreateSerializationException($"Failed to read type '{typeof(T).Name}'. Expected object start, got '{reader.TokenType}' <{reader.Value}>"); } reader.Read(); if (!(existingValue is T value)) { value = new T(); } string previousName = null; while (reader.TokenType == JsonToken.PropertyName) { if (reader.Value is string name) { if (name == previousName) { throw reader.CreateSerializationException($"Failed to read type '{typeof(T).Name}'. Possible loop when reading property '{name}'"); } previousName = name; ReadValue(ref value, name, reader, serializer); } else { reader.Skip(); } reader.Read(); } return value; } /// /// Write the specified properties of the object. /// /// The Newtonsoft.Json.JsonWriter to write to. /// The value. /// The calling serializer. public override void WriteJson(JsonWriter writer, [AllowNull] object value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } writer.WriteStartObject(); var typed = (T)value; WriteJsonProperties(writer, typed, serializer); writer.WriteEndObject(); } } }