using System; using System.Diagnostics; using System.IO.Abstractions; using System.Linq; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; namespace Quadarax.Foundation.Core.Json { public class Binder { private IFileSystem _fileSystem; public JsonSerializerOptions SerializerOptions {get;private set;} public Binder(JsonSerializerOptions options): this(new FileSystem(), options) { } public Binder(IFileSystem fileSystemAbstraction, JsonSerializerOptions options) { _fileSystem = fileSystemAbstraction ?? throw new ArgumentNullException(nameof(fileSystemAbstraction)); SerializerOptions = options; } public Binder(IFileSystem fileSystemAbstraction, bool isPrettyPrint = true, bool isIgnoringNullValues = true, int maxDepth = 100) { _fileSystem = fileSystemAbstraction ?? throw new ArgumentNullException(nameof(fileSystemAbstraction)); var jsonOpt = new JsonSerializerOptions { WriteIndented = isPrettyPrint, PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, MaxDepth = maxDepth }; if (isIgnoringNullValues) jsonOpt.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; jsonOpt.Converters.Add(new JsonStringEnumConverter()); SerializerOptions = jsonOpt; } public TObject? Load(string fileName) { return (TObject?) Load(fileName, typeof(TObject)); } public object? Load(string fileName, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); using (var reader = _fileSystem.File.OpenText(fileName)) { var result = JsonSerializer.Deserialize(reader.ReadToEnd(),targetType, SerializerOptions); return result; } } public object? LoadFromString(string jsonString, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); if (string.IsNullOrEmpty(jsonString)) throw new ArgumentNullException(nameof(jsonString)); var result = JsonSerializer.Deserialize(jsonString,targetType, SerializerOptions); return result; } public void LoadTo(string fileName, object target, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); if (target == null) throw new ArgumentNullException(nameof(target)); var shadow = Load(fileName, targetType); if (shadow == null) throw new InvalidOperationException($"Cannot load file '{fileName}' to '{targetType.FullName}'"); foreach (var property in shadow.GetType().GetProperties()) { if (target.GetType().GetProperties().Any(x => x.Name == property.Name && property.GetValue(shadow) != null)) { if (property.GetType().IsClass && property.PropertyType.Assembly.FullName == targetType.Assembly.FullName) { var mapMethod = typeof(Binder).GetMethod("LoadTo"); var shadowValue = property.GetValue(shadow); var shadowType = property.GetValue(shadow)?.GetType() ?? property.PropertyType; var genericMethod = mapMethod?.MakeGenericMethod(shadowType); var obj2 = genericMethod?.Invoke(null, new object?[] { shadowValue, JsonSerializer.Serialize(property.GetValue(shadow)) }); if (obj2 != null) { foreach (var property2 in obj2.GetType().GetProperties()) { if (property2.GetValue(obj2) != null) { (property.GetValue(target)?.GetType() ?? property.PropertyType).GetProperty( property2.Name)!.SetValue(property.GetValue(target), property2.GetValue(obj2)); } } } } else if (property.CanWrite) { property.SetValue(target, property.GetValue(shadow)); } } } } public void LoadFromStringTo(string jsonString, object target, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); if (target == null) throw new ArgumentNullException(nameof(target)); var shadow = LoadFromString(jsonString, targetType); if(shadow == null) throw new InvalidOperationException($"Cannot load object ({targetType.FullName}) from json string."); foreach (var property in shadow.GetType().GetProperties()) { if (target.GetType().GetProperties().Any(x => x.Name == property.Name && property.GetValue(shadow) != null)) { if (property.GetType().IsClass && property.PropertyType.Assembly.FullName == targetType.Assembly.FullName) { var mapMethod = typeof(Binder).GetMethod("LoadFromStringTo"); var shadowType = property.GetValue(shadow)?.GetType() ?? property.PropertyType; var genericMethod = mapMethod?.MakeGenericMethod(shadowType); var obj2 = genericMethod?.Invoke(null, new object?[] { property.GetValue(shadow), JsonSerializer.Serialize(property.GetValue(shadow)) }); if (obj2 != null) { foreach (var property2 in obj2.GetType().GetProperties()) { if (property2.GetValue(obj2) != null) { property?.GetValue(target)?.GetType()?.GetProperty(property2.Name)? .SetValue(property.GetValue(target), property2.GetValue(obj2)); } } } } else if (property.CanWrite) { property.SetValue(target, property.GetValue(shadow)); } } } } public void LoadTo(string fileName, TObject target) { if (target == null) throw new ArgumentNullException(nameof(target)); LoadTo(fileName, target, typeof(TObject)); } public void Save(string fileName, TObject bindingObject) { if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); if (bindingObject==null) throw new ArgumentNullException(nameof(bindingObject)); var configuration = JsonSerializer.SerializeToUtf8Bytes(bindingObject,SerializerOptions); using (var writer = _fileSystem.File.Create(fileName)) { writer.Write(configuration); writer.Flush(); } } public string SaveToString(TObject bindingObject) { if (bindingObject==null) throw new ArgumentNullException(nameof(bindingObject)); return JsonSerializer.Serialize(bindingObject,bindingObject.GetType()); } } }