-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRTEJsonConverter.cs
More file actions
169 lines (143 loc) · 6.76 KB
/
Copy pathRTEJsonConverter.cs
File metadata and controls
169 lines (143 loc) · 6.76 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using System;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Contentstack.Utils.Interfaces;
namespace Contentstack.Utils.Converters
{
/// <summary>
/// Factory for JSON path-based deserialization used by <see cref="Models.JsonRTENode{T}"/> and <see cref="Models.JsonRTENodes{T}"/>.
/// </summary>
public sealed class RTEJsonConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
return false;
Type def = typeToConvert.GetGenericTypeDefinition();
return def == typeof(Models.JsonRTENode<>) || def == typeof(Models.JsonRTENodes<>);
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Type embeddedArg = typeToConvert.GetGenericArguments()[0];
Type def = typeToConvert.GetGenericTypeDefinition();
if (def == typeof(Models.JsonRTENode<>))
{
Type converterType = typeof(RTEJsonConverterImpl<>).MakeGenericType(embeddedArg);
return (JsonConverter)Activator.CreateInstance(converterType);
}
if (def == typeof(Models.JsonRTENodes<>))
{
Type converterType = typeof(RTEJsonNodesConverterImpl<>).MakeGenericType(embeddedArg);
return (JsonConverter)Activator.CreateInstance(converterType);
}
throw new InvalidOperationException($"Unsupported type for RTE JSON converter: {typeToConvert}");
}
}
/// <summary>
/// Deserializes objects whose properties map to dotted JSON paths (same idea as Newtonsoft <c>SelectToken</c> with <see cref="JsonPropertyNameAttribute"/>).
/// </summary>
public sealed class PathMappedJsonConverter<T> : JsonConverter<T>
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
JsonObject jo = JsonNode.Parse(ref reader) as JsonObject ?? new JsonObject();
T targetObj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in typeof(T).GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyNameAttribute att = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
string jsonPath = att?.Name ?? prop.Name;
JsonNode token = RTEJsonPath.SelectPath(jo, jsonPath);
if (token != null && !RTEJsonPath.IsJsonNull(token))
{
object value = RTEJsonPath.DeserializeNode(token, prop.PropertyType, options);
prop.SetValue(targetObj, value);
}
}
return targetObj;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
throw new NotSupportedException("Serialization is not supported for path-mapped RTE models.");
}
}
internal static class RTEJsonPath
{
internal static JsonNode SelectPath(JsonObject root, string path)
{
if (root == null || string.IsNullOrEmpty(path))
return null;
string[] segments = path.Split('.');
JsonNode current = root;
foreach (string segment in segments)
{
if (current is JsonObject jo && jo.TryGetPropertyValue(segment, out JsonNode next))
current = next;
else
return null;
}
return current;
}
internal static bool IsJsonNull(JsonNode node)
{
if (node == null)
return true;
return node is JsonValue jv && jv.GetValueKind() == JsonValueKind.Null;
}
internal static object DeserializeNode(JsonNode token, Type propertyType, JsonSerializerOptions options)
{
string json = token.ToJsonString(options);
return JsonSerializer.Deserialize(json, propertyType, options);
}
}
internal sealed class RTEJsonConverterImpl<T> : JsonConverter<Models.JsonRTENode<T>> where T : IEmbeddedObject
{
public override Models.JsonRTENode<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
JsonObject jo = JsonNode.Parse(ref reader) as JsonObject ?? new JsonObject();
var targetObj = new Models.JsonRTENode<T>();
foreach (PropertyInfo prop in typeof(Models.JsonRTENode<T>).GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyNameAttribute att = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
string jsonPath = att?.Name ?? prop.Name;
JsonNode token = RTEJsonPath.SelectPath(jo, jsonPath);
if (token != null && !RTEJsonPath.IsJsonNull(token))
{
object value = RTEJsonPath.DeserializeNode(token, prop.PropertyType, options);
prop.SetValue(targetObj, value);
}
}
return targetObj;
}
public override void Write(Utf8JsonWriter writer, Models.JsonRTENode<T> value, JsonSerializerOptions options)
{
throw new NotSupportedException("Serialization is not supported for JsonRTENode.");
}
}
internal sealed class RTEJsonNodesConverterImpl<T> : JsonConverter<Models.JsonRTENodes<T>> where T : IEmbeddedObject
{
public override Models.JsonRTENodes<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
JsonObject jo = JsonNode.Parse(ref reader) as JsonObject ?? new JsonObject();
var targetObj = new Models.JsonRTENodes<T>();
foreach (PropertyInfo prop in typeof(Models.JsonRTENodes<T>).GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyNameAttribute att = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
string jsonPath = att?.Name ?? prop.Name;
JsonNode token = RTEJsonPath.SelectPath(jo, jsonPath);
if (token != null && !RTEJsonPath.IsJsonNull(token))
{
object val = RTEJsonPath.DeserializeNode(token, prop.PropertyType, options);
prop.SetValue(targetObj, val);
}
}
return targetObj;
}
public override void Write(Utf8JsonWriter writer, Models.JsonRTENodes<T> value, JsonSerializerOptions options)
{
throw new NotSupportedException("Serialization is not supported for JsonRTENodes.");
}
}
}