123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- using System;
- using System.Linq;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
-
- namespace Luticate2.Auth.Business.Serializers.PartialJson
- {
- /// <summary>
- /// Provides a method for serializing objects to JSON.
- /// </summary>
- /// <remarks>This type supports the <see cref="PartialResponse.Core.Fields"/> infrastructure and is not intended to be used directly
- /// from your code.</remarks>
- public static class LuJsonSerializerExtensions
- {
- /// <summary>
- /// Serializes the specified <see cref="object"/> and writes the JSON structure
- /// using the specified <see cref="JsonWriter"/>.
- /// </summary>
- /// <param name="jsonSerializer">The <see cref="JsonSerializer"/> used to serialize the specified <see cref="object"/>.</param>
- /// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the JSON structure.</param>
- /// <param name="value">The <see cref="object"/> to serialize.</param>
- /// <param name="shouldSerialize">A <see cref="Func{T, TResult}"/> that is called for every field in the
- /// <see cref="object"/> to serialize, indicating whether the field should be serialized.</param>
- public static void Serialize(this JsonSerializer jsonSerializer, JsonWriter jsonWriter, object value, Func<string, bool> shouldSerialize)
- {
- if (value == null)
- {
- jsonSerializer.Serialize(jsonWriter, value);
- }
- else
- {
- var context = new LuSerializerContext(shouldSerialize);
- var token = JToken.FromObject(value, jsonSerializer);
-
- if (token is JArray array)
- {
- RemoveArrayElements(array, null, context);
-
- array.WriteTo(jsonWriter);
- }
- else
- {
- if (token is JObject @object)
- {
- RemoveObjectProperties(@object, null, context);
-
- @object.WriteTo(jsonWriter);
- }
- else
- {
- token.WriteTo(jsonWriter);
- }
- }
- }
- }
-
- private static void RemoveArrayElements(JArray array, string currentPath, LuSerializerContext context)
- {
- var containsChildItems = array.Count > 0;
-
- array.OfType<JObject>()
- .ToList()
- .ForEach(childObject => RemoveObjectProperties(childObject, currentPath, context));
-
- // PartialResponse should only remove an array when it initially contained items, but was empty after filtering.
- if (containsChildItems)
- {
- RemoveArrayIfEmpty(array);
- }
- }
-
- private static void RemoveArrayIfEmpty(JArray array)
- {
- if (array.Count == 0)
- {
- if (array.Parent is JProperty && array.Parent.Parent != null)
- {
- array.Parent.Remove();
- }
- else if (array.Parent is JArray)
- {
- array.Remove();
- }
- }
- }
-
- private static void RemoveObjectProperties(JObject @object, string currentPath, LuSerializerContext context)
- {
- @object.Properties()
- .Where(property =>
- {
- var path = CombinePath(currentPath, property.Name);
-
- return !context.ShouldSerialize(path);
- })
- .ToList()
- .ForEach(property => property.Remove());
-
- @object.Properties()
- .Where(property => property.Value is JObject)
- .ToList()
- .ForEach(property =>
- {
- var path = CombinePath(currentPath, property.Name);
-
- RemoveObjectProperties((JObject)property.Value, path, context);
- });
-
- @object.Properties()
- .Where(property => property.Value is JArray)
- .ToList()
- .ForEach(property =>
- {
- var path = CombinePath(currentPath, property.Name);
-
- RemoveArrayElements((JArray)property.Value, path, context);
- });
-
- RemoveObjectIfEmpty(@object);
- }
-
- private static void RemoveObjectIfEmpty(JObject @object)
- {
- if (!@object.Properties().Any())
- {
- if (@object.Parent is JProperty && @object.Parent.Parent != null)
- {
- @object.Parent.Remove();
- }
- else if (@object.Parent is JArray)
- {
- @object.Remove();
- }
- }
- }
-
- private static string CombinePath(string path, string name)
- {
- if (string.IsNullOrEmpty(path))
- {
- return name;
- }
-
- return $"{path}/{name}";
- }
- }
- }
|