private void ReadFlattenedJsonIntoObject(object finalResult, IDictionary <string, object> flattenedJson) { Type objectType = finalResult.GetType(); JsonClassAttribute jsonClassAttribute = objectType.GetCustomAttribute <JsonClassAttribute>(); PropertyInfo[] propertiesToDeserialize = objectType.GetProperties(); foreach (PropertyInfo propToDeserialize in propertiesToDeserialize) { JsonPropertyAttribute jsonPropertyAttribute = propToDeserialize.GetCustomAttribute <JsonPropertyAttribute>(true); string flatJsonLookupKey; bool isJsonPropertyAttributeValueASelector; if (jsonPropertyAttribute != null) { isJsonPropertyAttributeValueASelector = jsonPropertyAttribute.PropertyName.Split(',').Any(y => y == "{}" || y == "[]"); flatJsonLookupKey = this.PascalizePath(jsonPropertyAttribute.PropertyName); } else { isJsonPropertyAttributeValueASelector = false; flatJsonLookupKey = propToDeserialize.Name.Pascalize(); } if (jsonClassAttribute?.IsEnumerablePath == false) { flatJsonLookupKey = $"{this.PascalizePath(jsonClassAttribute.Path)}.{flatJsonLookupKey}"; } string flatJsonLookupKeyParent; if (isJsonPropertyAttributeValueASelector) { flatJsonLookupKeyParent = this.GetFirstFlatKeyThatMatchesSelector(flatJsonLookupKey, flattenedJson); } else { flatJsonLookupKeyParent = this.GetFlatKeyParent(flatJsonLookupKey); } Type propertyTypeUnderlying = Nullable.GetUnderlyingType(propToDeserialize.PropertyType) ?? propToDeserialize.PropertyType; if (Type.GetTypeCode(propertyTypeUnderlying) == TypeCode.Object) { // Get get all the props for that object Dictionary <string, object> propsForDeserializingObject = flattenedJson .Where(y => y.Key.StartsWith($"{flatJsonLookupKeyParent}.") || y.Key.StartsWith($"{flatJsonLookupKeyParent}[")) .ToDictionary( // and then trim the parent from the dictionary keySelector: y => { string newKey = y.Key.Substring(flatJsonLookupKeyParent.Length); if (newKey.StartsWith(".")) { newKey = newKey.Substring(1); } return(newKey); }, elementSelector: y => y.Value); object result = this.ReadFlattenedJsonIntoTargetObjectType(propsForDeserializingObject, propToDeserialize.PropertyType); propToDeserialize.SetValue(finalResult, result); } else { if (!flattenedJson.TryGetValue(flatJsonLookupKey, out object flatJsonLookupValue)) { if (jsonPropertyAttribute == null) { continue; } if (flattenedJson.TryGetValue(flatJsonLookupKeyParent, out object flatJsonLookupKeyParentObject)) { // If the key exists, but the value is null, it's ok, don't throw any error. if (flatJsonLookupKeyParentObject == null) { continue; } } continue; } if (flatJsonLookupValue != null) { Type underlyingPropertyType = Nullable.GetUnderlyingType(propToDeserialize.PropertyType); flatJsonLookupValue = Convert.ChangeType(flatJsonLookupValue, underlyingPropertyType ?? propToDeserialize.PropertyType); } propToDeserialize.SetValue(finalResult, flatJsonLookupValue); } } }
private void ReadFlattenedJsonIntoList(IList finalList, IDictionary <string, object> flattenedJson) { Type objectType = finalList.GetType(); JsonClassAttribute jsonClassAttribute = objectType.GetCustomAttribute <JsonClassAttribute>(); Type underlyingEnumerableType = objectType .GetInterfaces() .FirstOrDefault(y => typeof(IEnumerable <object>).IsAssignableFrom(y)) .GetGenericArguments() .FirstOrDefault(); if (jsonClassAttribute == null) { jsonClassAttribute = underlyingEnumerableType.GetCustomAttribute <JsonClassAttribute>(); } string jsonClassAttributePath = jsonClassAttribute?.Path ?? ""; jsonClassAttributePath = this.PascalizePath(jsonClassAttributePath); // Key all the keys which start with the JsonClassAttribute's path // And group them by the array index var groupedFlattenJsonByArrayIndex = flattenedJson // Must start with an array square bracket .Where(y => y.Key.StartsWith($"{jsonClassAttributePath}")) .GroupBy(y => { int indexOfArray = y.Key.IndexOf("["); if (indexOfArray == -1) { return(""); } // The array is part of a nested object, not the direct object if (y.Key.IndexOf(".") < indexOfArray) { return(""); } string pathToArray = y.Key.Substring(0, indexOfArray); if (!pathToArray.EndsWith(jsonClassAttributePath)) { return(""); } string index = y.Key.Substring(indexOfArray + 1); index = index.Substring(0, index.IndexOf("]")); return(index); }); foreach (var group in groupedFlattenJsonByArrayIndex) { Dictionary <string, object> arrayItemDictionary; if (!String.IsNullOrEmpty(group.Key)) { arrayItemDictionary = group.ToDictionary( keySelector: y => { string newKey = y.Key.Substring(y.Key.IndexOf("]") + 1); if (newKey.StartsWith(".")) { newKey = newKey.Substring(1); } return(newKey); }, elementSelector: pair => pair.Value); } else { arrayItemDictionary = group.ToDictionary(y => y.Key, y => y.Value); } object targetObjectResult = this.ReadFlattenedJsonIntoTargetObjectType(arrayItemDictionary, underlyingEnumerableType); finalList.Add(targetObjectResult); } }