-
Notifications
You must be signed in to change notification settings - Fork 185
Expand file tree
/
Copy pathColumnizerJsonConverter.cs
More file actions
119 lines (102 loc) · 4.23 KB
/
ColumnizerJsonConverter.cs
File metadata and controls
119 lines (102 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System.Reflection;
using LogExpert.Core.Classes.Attributes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace LogExpert.Core.Classes.JsonConverters;
/// <summary>
/// Custom JsonConverter for ILogLineColumnizer implementations.
/// Serializes only properties marked with [JsonColumnizerProperty].
/// Uses GetName() for type identification.
/// </summary>
public class ColumnizerJsonConverter : JsonConverter
{
public override bool CanConvert (Type objectType)
{
return typeof(ILogLineColumnizer).IsAssignableFrom(objectType);
}
public override void WriteJson (JsonWriter writer, object? value, JsonSerializer serializer)
{
ArgumentNullException.ThrowIfNull(writer);
ArgumentNullException.ThrowIfNull(value);
if (value is not ILogLineColumnizer columnizer)
{
writer.WriteNull();
return;
}
var type = value.GetType();
var stateObj = new JObject();
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (prop.GetCustomAttribute<JsonColumnizerPropertyAttribute>() != null && prop.CanRead)
{
var propValue = prop.GetValue(value);
stateObj[prop.Name] = propValue != null ? JToken.FromObject(propValue, serializer) : JValue.CreateNull();
}
}
writer.WriteStartObject();
writer.WritePropertyName("Type");
writer.WriteValue(columnizer.GetName());
writer.WritePropertyName("State");
stateObj.WriteTo(writer);
writer.WriteEndObject();
}
public override object ReadJson (JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
ArgumentNullException.ThrowIfNull(reader);
if (reader.TokenType == JsonToken.Null)
{
return null;
}
var jObject = JObject.Load(reader);
var typeName = jObject["Type"]?.ToString();
if (typeName == null || jObject["State"] is not JObject state)
{
return null;
}
// Find the columnizer type by GetName()
var columnizerType = FindColumnizerTypeByName(typeName) ?? throw new JsonSerializationException($"Columnizer type '{typeName}' not found.");
var instance = Activator.CreateInstance(columnizerType);
foreach (var prop in columnizerType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (prop.GetCustomAttribute<JsonColumnizerPropertyAttribute>() != null && prop.CanWrite)
{
var token = state[prop.Name];
if (token != null && token.Type != JTokenType.Null)
{
var value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(instance, value);
}
}
}
return instance;
}
private static Type FindColumnizerTypeByName (string name)
{
// Search all loaded assemblies for a type implementing ILogLineColumnizer with matching GetName()
foreach (var currentAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in currentAssembly.GetTypes().Where(t => typeof(ILogLineColumnizer).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract))
{
try
{
if (Activator.CreateInstance(type) is ILogLineColumnizer instance && instance.GetName() == name)
{
return type;
}
}
catch (Exception ex) when (ex is ArgumentNullException or
ArgumentException or
NotSupportedException or
TargetInvocationException or
MethodAccessException or
MemberAccessException or
MissingMethodException or
TypeLoadException)
{
// intentionally ignored
}
}
}
return null;
}
}