using System.Reflection; using adas_core.Domain.Models; using MongoDB.Bson.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; namespace adas_core.Infrastructure.Utils; /// /// Provides JSON conversion for the type via and also implements BSON serialization through . /// /// /// The primary constructor accepts a that represents the value type associated with this converter. /// public class PersonConverter(Type valueType) : JsonConverter, IBsonSerializer { /// /// Deserializes a BSON value into a .NET object using the provided context and arguments. /// /// The BSON deserialization context. /// The BSON deserialization arguments. /// The deserialized object. /// Always thrown because the method is not yet implemented. public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { throw new NotImplementedException(); } /// /// Serializes the specified object to BSON format using the provided serialization context and arguments. The method is not implemented and always throws an exception. /// /// The BSON serialization context that provides the writer and configuration for the operation. /// The BSON serialization arguments containing additional settings for the serialization. /// The object to be serialized to BSON. /// Always thrown because the method has not been implemented yet. public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { throw new NotImplementedException(); } public Type ValueType { get; } = valueType; /// /// Serializes a instance to JSON, ensuring the Gender property is written using string-based enum representation. Does nothing when the provided value is . /// /// The to which the JSON representation is written. /// The instance to serialize. If , the method returns without writing anything. /// The used during the conversion to a . public override void WriteJson(JsonWriter writer, Person? value, JsonSerializer serializer) { if (value == null) return; var jo = JObject.FromObject(value); // Add [JsonConverter(typeof(StringEnumConverter))] attribute to specified properties AddStringEnumConverterAttribute(value, "Gender"); jo.WriteTo(writer); } /// /// Adds a StringEnumConverter JSON converter attribute to the specified property if one is not already applied, ensuring enum values are serialized as strings. The method returns silently if the property is not found on the value's type or if a JsonConverterAttribute is already present. /// /// The object instance whose property's attributes will be inspected and modified. /// The name of the property to which the converter attribute will be added. private static void AddStringEnumConverterAttribute(object value, string propertyName) { var prop = value.GetType().GetProperty(propertyName); var attr = new JsonConverterAttribute(typeof(StringEnumConverter)); if (prop == null) return; var attrs = prop.GetCustomAttributes(false); // Check if the attribute is not already applied if (Array.Find(attrs, a => a is JsonConverterAttribute) != null) return; // Create a new array that includes the existing attributes and the new one var newAttrs = new object[attrs.Length + 1]; Array.Copy(attrs, newAttrs, attrs.Length); newAttrs[attrs.Length] = attr; // Use reflection to set the new attributes array var field = typeof(PropertyInfo).GetField("m_customAttributes", BindingFlags.Instance | BindingFlags.NonPublic); field?.SetValue(prop, newAttrs); } /// /// Reads the JSON representation of a object. This override is not yet implemented. /// /// The to read from. /// The type of the object to deserialize. /// The existing value of the object being read, or null if there is no existing value. /// A value indicating whether has a value. /// The calling the method. /// A instance deserialized from the JSON. /// Always thrown because the method has not been implemented. public override Person ReadJson(JsonReader reader, Type objectType, Person? existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); } }