Esempio n. 1
0
        /// <summary>
        /// Builds an object from the provided <see cref="Json"/>.
        /// </summary>
        /// <param name="type">The type of object to build</param>
        /// <param name="sourceJson">The <see cref="Json"/> used</param>
        /// <param name="settings">Special interpretter settings</param>
        /// <returns>The object built from the <see cref="Json"/></returns>
        public static object BuildObjectForJson(Type type, Json sourceJson, JsonInterpretterSettings settings = null)
        {
            if (sourceJson.HasErrors)
            {
                return(null);
            }

            return(BuildObjectForJson(type, sourceJson.Data, settings));
        }
Esempio n. 2
0
        /// <summary>
        /// Build an object for json that has been typed (using the built in <see cref="JsonDocument.kTypeIndicator"/> property)
        /// </summary>
        public static object BuildObjectForTypedJson(JsonValue sourceJson, JsonInterpretterSettings settings = null)
        {
            if (sourceJson is JsonDocument doc &&
                doc.ValueFor(JsonDocument.kTypeIndicator) is JsonValue typeValue &&
                !String.IsNullOrEmpty(typeValue.StringValue) &&
                TypesByTypeId.TryGetValue(typeValue.StringValue, out Type objectType))
            {
                return(BuildObjectForJson(objectType, sourceJson, settings));
            }

            return(null);
        }
Esempio n. 3
0
        /// <summary>
        /// Fills out an existing instance with <see cref="JsonValue"/>.
        /// </summary>
        /// <param name="targetItem">The instance to fill out</param>
        /// <param name="sourceJsonValue">The <see cref="JsonValue"/> used</param>
        /// <param name="settings">Special interpretter settings</param>
        public static void FillOutObjectWithJson(ref object targetItem, JsonValue sourceJsonValue, JsonInterpretterSettings settings = null)
        {
            Type targetType = targetItem.GetType();

            settings = settings ?? JsonInterpretterSettings.Default;

            if (sourceJsonValue.IsValue)
            {
                if (settings.StringParser.CanConvert(targetType))
                {
                    targetItem = settings.StringParser.Convert(sourceJsonValue.StringValue, targetType);
                }

                return;
            }
            if (sourceJsonValue.IsArray)
            {
                bool       isArray = false, isList = false, isDictionary = false;
                Type       elementType   = null;
                MethodInfo dictionaryAdd = null;
                if (targetType.IsArray)
                {
                    isArray     = true;
                    elementType = targetType.GetElementType();
                }
                else if (targetType.FindBaseTypeOrInterface(typeof(IList <>)) is Type listType)
                {
                    isList      = true;
                    elementType = listType.GetGenericArguments()[0];
                }
                else if (targetType.FindBaseTypeOrInterface(typeof(IDictionary <,>)) is Type dictionaryType)
                {
                    isDictionary = true;
                    var generics = dictionaryType.GetGenericArguments();
                    elementType = typeof(KeyValuePair <,>).MakeGenericType(generics[0], generics[1]);

                    var collectionType = typeof(ICollection <>).MakeGenericType(elementType);
                    dictionaryAdd = collectionType.GetMethod("Add", new[] { elementType });
                    Debug.Assert(dictionaryAdd != null, $"Could not find add method for dictionary of type {targetType}");
                }

                JsonArray sourceCasted = (JsonArray)sourceJsonValue;
                for (int index = 0; index < sourceCasted.Count; ++index)
                {
                    JsonValue value   = sourceCasted[index];
                    object    element = BuildObjectForJson(elementType, value, settings);

                    // If it's an array, then we've preallocated it the correct length already
                    if (isArray)
                    {
                        ((IList)targetItem)[index] = element;
                    }
                    else if (isList)
                    {
                        ((IList)targetItem).Insert(index, element);
                    }
                    else if (isDictionary)
                    {
                        dictionaryAdd.Invoke(targetItem, new object[] { element });
                    }
                }
            }
            if (sourceJsonValue.IsDocument)
            {
                JsonDocument   sourceCasted  = (JsonDocument)sourceJsonValue;
                PropertyInfo[] allProperties = GetPropertiesFrom(targetType, false, true
#if WINDOWS_UWP
                                                                 // Unfortunately, there aren't these kinds of settings in this direciton
                                                                 //  going to say that opt in IS NOT required for this way anyway for now
                                                                 , false
#endif
                                                                 );

                foreach (var kvp in sourceCasted)
                {
                    if (kvp.Key == JsonDocument.kTypeIndicator)
                    {
                        continue;
                    }

                    PropertyInfo propToSet = allProperties.FirstOrDefault(prop => prop.Name == kvp.Key);
                    if (propToSet != null)
                    {
                        object newPropValue = null;

                        // Resolve runtime type evaluation
                        var runtimeTypeEval = propToSet.GetAttributes <JsonRuntimeTypeEvalAttribute>()?.FirstOrDefault();
                        if (runtimeTypeEval != null && kvp.Value.IsDocument)
                        {
                            JsonDocument valueDocCasted = (JsonDocument)kvp.Value;
                            if (valueDocCasted.TryGetValue(JsonDocument.kTypeIndicator, out string typeIdForValue) &&
                                valueDocCasted.ValueFor(JsonDocument.kRuntimeTypeEvalValue) is JsonValue foundRuntimeValueIndicator &&
                                JsonHelper.TryGetTypeForTypeId(typeIdForValue, out Type foundType))
                            {
                                newPropValue = BuildObjectForJson(foundType, foundRuntimeValueIndicator, settings);
                            }
                        }

                        // If we're not dealing with runtime type evaluation, use the property type
                        if (newPropValue == null)
                        {
                            newPropValue = BuildObjectForJson(propToSet.PropertyType, kvp.Value, settings);
                        }

                        propToSet.SetValue(targetItem, newPropValue);
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Builds an object from the provided <see cref="Json"/>.
        /// </summary>
        /// <param name="type">The type of object to build</param>
        /// <param name="sourceJsonValue">The <see cref="JsonValue"/> used</param>
        /// <param name="settings">Special interpretter settings</param>
        /// <returns>The object built from the <see cref="JsonValue"/></returns>
        public static object BuildObjectForJson(Type type, JsonValue sourceJsonValue, JsonInterpretterSettings settings = null)
        {
            if (typeof(JsonValue).IsAssignableFrom(type))
            {
                return(sourceJsonValue);
            }

            settings = settings ?? JsonInterpretterSettings.Default;
            object outputInstance = null;

            // If we're elevating one of the properties of this thing, as itself, then we need to
            //  alter the type we're operating on
            string elevatedPropertyName = type.GetAttributes <JsonPropertyAsSelfAttribute>()?.FirstOrDefault()?.PropertyName;

            if (elevatedPropertyName != null)
            {
                // If we're doing elevation, then we are dealing with an object at this point
                //  we'll need to create the instance, and set the value on the property indicated
                PropertyInfo targetProp = type.GetProperty(elevatedPropertyName, BindingFlags.Public | BindingFlags.Instance);
                if (targetProp != null)
                {
                    outputInstance = Activator.CreateInstance(type);

                    // Basically forward the json value onto building the child, and set value of that to the output instance
                    object childInstance = BuildObjectForJson(targetProp.PropertyType, sourceJsonValue, settings);
                    targetProp.SetValue(outputInstance, childInstance);

                    return(outputInstance);
                }
            }

            if (sourceJsonValue.IsDocument)
            {
                JsonDocument docVersion    = (JsonDocument)sourceJsonValue;
                string       typeIndicator = docVersion.ValueFor(JsonDocument.kTypeIndicator)?.StringValue;
                if (typeIndicator != null)
                {
                    if (TryGetTypeForTypeId(typeIndicator, out Type targetType))
                    {
                        outputInstance = Activator.CreateInstance(targetType);
                    }
                    else
                    {
                        Logger.LogError($"Target type provided {typeIndicator ?? "-null-"} could not be translated, skipping");
                    }
                }
            }
            else if (sourceJsonValue.IsArray)
            {
                var array = (JsonArray)sourceJsonValue;

                // You have to create arrays with an argument
                if (type.IsArray)
                {
                    outputInstance = Activator.CreateInstance(type, array.Count);
                }
            }

            if (outputInstance == null)
            {
                outputInstance = settings.ConstructInstanceFor(type, sourceJsonValue);
            }

            FillOutObjectWithJson(ref outputInstance, sourceJsonValue, settings);
            return(outputInstance);
        }
Esempio n. 5
0
 /// <summary>
 /// Build an object for json that has been typed (using the built in <see cref="JsonDocument.kTypeIndicator"/> property)
 /// </summary>
 public static object BuildObjectForTypedJson(Json sourceJson, JsonInterpretterSettings settings = null)
 {
     return(sourceJson.HasErrors ? null : BuildObjectForTypedJson(sourceJson.Data, settings));
 }
Esempio n. 6
0
        /// <summary>
        /// Builds a list of objects from the <see cref="JsonArray"/>
        /// </summary>
        /// <typeparam name="T">The type of object to build</typeparam>
        /// <param name="sourceJsonArray">The <see cref="JsonValue"/> being evaluated</param>
        /// <param name="settings">Special interpretter settings</param>
        /// <returns>A list built with objects parsed from the array</returns>
        public static List <T> BuildObjectListForJson <T> (JsonArray sourceJsonArray, JsonInterpretterSettings settings = null)
        {
            var list = new List <T>();

            foreach (JsonValue value in sourceJsonArray)
            {
                list.Add(BuildObjectForJson <T>(value, settings));
            }

            return(list);
        }
Esempio n. 7
0
 /// <summary>
 /// Builds an object from the provided <see cref="Json"/>.
 /// </summary>
 /// <typeparam name="T">The type of object to build</typeparam>
 /// <param name="sourceJsonValue">The <see cref="JsonValue"/> used</param>
 /// <param name="settings">Special interpretter settings</param>
 /// <returns>The object built from the <see cref="JsonValue"/></returns>
 public static T BuildObjectForJson <T> (JsonValue sourceJsonValue, JsonInterpretterSettings settings = null)
 {
     return((T)BuildObjectForJson(typeof(T), sourceJsonValue, settings));
 }