Notification class selection based on type property
This commit is contained in:
parent
920187e876
commit
70d1b79a14
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace HabitSharp {
|
||||
namespace HabitSharp.Notifications {
|
||||
public class Notification {
|
||||
public Guid Id { get; set; }
|
||||
public bool Seen { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ using RestSharp.Serializers;
|
|||
using RestSharp.Deserializers;
|
||||
|
||||
namespace HabitSharp.Serialization {
|
||||
/// <summary>
|
||||
/// A RestSharp Serializer and Deserializer that uses Newtonsoft.Json
|
||||
/// </summary>
|
||||
public class NewtonsoftJsonSerializer : ISerializer, IDeserializer
|
||||
{
|
||||
private Newtonsoft.Json.JsonSerializer serializer;
|
||||
|
@ -44,9 +47,14 @@ namespace HabitSharp.Serialization {
|
|||
}
|
||||
}
|
||||
|
||||
public static NewtonsoftJsonSerializer Default =>
|
||||
new NewtonsoftJsonSerializer(new Newtonsoft.Json.JsonSerializer() {
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
});
|
||||
public static NewtonsoftJsonSerializer Default {
|
||||
get {
|
||||
var ser = new Newtonsoft.Json.JsonSerializer() {
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
};
|
||||
ser.Converters.Add(new NotificationConverter());
|
||||
return new NewtonsoftJsonSerializer(ser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using HabitSharp.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// A converter to create subclasses of Notification when possible to fetch more information.
|
||||
/// If a notification is of an unknown type, will create a simple Notification class.
|
||||
/// </summary>
|
||||
/// <remarks>Serialization to JSON is not supported; this converter can only perform deserialization.</remarks>
|
||||
public class NotificationConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a class derived from Notification is there is one matching the given notification type, or return Notification if none is found.
|
||||
/// </summary>
|
||||
/// <param name="notificationType">The notification type string from JSON data.</param>
|
||||
/// <returns>System.Type for the Notification class or one of its derived classes</returns>
|
||||
public Type FindNotificationSubclass(string notificationType) {
|
||||
// Find all Notification subclasses in the same assembly
|
||||
return typeof(Notification).Assembly.GetTypes()
|
||||
.Where(t => t.IsSubclassOf(typeof(Notification)))
|
||||
.SingleOrDefault(
|
||||
// Find the only one subclass that has a NotificationType attribute with the right type string
|
||||
t => Attribute.GetCustomAttributes(t, typeof(NotificationTypeAttribute)).Any(
|
||||
attr => ((NotificationTypeAttribute)attr).TypeString.Equals(notificationType, StringComparison.InvariantCultureIgnoreCase)
|
||||
)
|
||||
) ?? typeof(Notification); // Default to the Notification class
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType) => objectType.IsSubclassOf(typeof(Notification)) || objectType == typeof(Notification);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject jo = JObject.Load(reader);
|
||||
Type noteClass = FindNotificationSubclass((string)jo["type"]);
|
||||
// Dirty hack to use a Type variable as a type in a generic method
|
||||
// TODO: There probably is a nicer way to do this.
|
||||
var method = typeof(JObject).GetMethod("ToObject").MakeGenericMethod(new Type[] { noteClass });
|
||||
return method.Invoke(jo, new object[] { serializer });
|
||||
}
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
public class NotificationTypeAttribute : Attribute {
|
||||
public readonly string TypeString;
|
||||
public NotificationTypeAttribute(string type) => this.TypeString = type;
|
||||
}
|
Reference in New Issue