예제 #1
0
        private static TypedDoc toTypedDoc(Type type, DocReadOptions?options, JsonDataMap jsonMap, ref string field, bool fromUI)
        {
            var toAllocate = type;

            var customHandler = JsonHandlerAttribute.TryFind(type);

            if (customHandler != null)
            {
                var castResult = customHandler.TypeCastOnRead(jsonMap, type, fromUI, options ?? DocReadOptions.BindByCode);

                if (castResult.Outcome >= JsonHandlerAttribute.TypeCastOutcome.ChangedTargetType)
                {
                    toAllocate = castResult.ToType.IsOfType(type, "Changed type must be a subtype of specific document type");
                }

                if (castResult.Outcome == JsonHandlerAttribute.TypeCastOutcome.ChangedSourceValue)
                {
                    jsonMap = (castResult.Value as JsonDataMap).NonNull("Changed source value must be of JsonDataMap type for root data documents");
                }
                else if (castResult.Outcome == JsonHandlerAttribute.TypeCastOutcome.HandledCast)
                {
                    return(castResult.Value.ValueIsOfType(type, "HandledCast must return TypedDoc for root data documents") as TypedDoc);
                }
            }

            if (toAllocate.IsAbstract)
            {
                throw new JSONDeserializationException(StringConsts.JSON_DESERIALIZATION_ABSTRACT_TYPE_ERROR.Args(toAllocate.Name, nameof(JsonHandlerAttribute)));
            }

            var doc = (TypedDoc)SerializationUtils.MakeNewObjectInstance(toAllocate);

            toDoc(doc, options.HasValue ? options.Value : DocReadOptions.BindByCode, jsonMap, ref field, fromUI);
            return(doc);
        }
예제 #2
0
        /// <summary>
        /// Converts JSONMap into supplied row instance.
        /// The extra data found in JSON map will be placed in AmorphousData dictionary if the row implements IAmorphousData, discarded otherwise.
        /// Note: This method provides "the best match" and does not guarantee that all data will/can be converted from JSON, i.e.
        ///  it can only convert one dimensional arrays and Lists of either primitive or TypeRow-derived entries
        /// </summary>
        /// <param name="doc">Data document instance to convert into</param>
        /// <param name="jsonMap">JSON data to convert into row</param>
        /// <param name="fromUI">When true indicates that data came from UI, hence NonUI-marked fields should be skipped. True by default</param>
        /// <param name="options">Used for backend name matching or null (any target)</param>
        public static void ToDoc(Doc doc, JsonDataMap jsonMap, bool fromUI = true, DocReadOptions?options = null)
        {
            if (doc == null || jsonMap == null)
            {
                throw new JSONDeserializationException(StringConsts.ARGUMENT_ERROR + "JSONReader.ToDoc(doc|jsonMap=null)");
            }

            var field = "";

            try
            {
                var tDoc          = doc.GetType();
                var customHandler = JsonHandlerAttribute.TryFind(tDoc);
                if (customHandler != null)
                {
                    var castResult = customHandler.TypeCastOnRead(jsonMap, tDoc, fromUI, options ?? DocReadOptions.BindByCode);

                    //only reacts to ChangeSource because this method works on pre-allocated doc
                    if (castResult.Outcome == JsonHandlerAttribute.TypeCastOutcome.ChangedSourceValue)
                    {
                        jsonMap = (castResult.Value as JsonDataMap).NonNull("Changed source value must be of JsonDataMap type for root data documents");
                    }
                }

                toDoc(doc, options.HasValue ? options.Value : DocReadOptions.BindByCode, jsonMap, ref field, fromUI);
            }
            catch (Exception error)
            {
                throw new JSONDeserializationException("JSONReader.ToDoc(doc, jsonMap) error in '{0}': {1}".Args(field, error.ToMessageWithType()), error);
            }
        }
예제 #3
0
        private static bool setOneField(Doc doc, Schema.FieldDef def, object fv, bool fromUI, DocReadOptions options)
        {
            var fieldCustomHandler = JsonHandlerAttribute.TryFind(def.MemberInfo);
            var converted          = cast(fv, def.Type, fromUI, options, fieldCustomHandler);

            if (converted != null)
            {
                doc.SetFieldValue(def, converted);
                return(true);
            }

            return(false);
        }//setOneField
예제 #4
0
        }//setOneField

        //Returns non null on success; may return null for collection sub-element in which case null=null and does not indicate failure
        private static object cast(object v, Type toType, bool fromUI, DocReadOptions options, JsonHandlerAttribute fieldCustomHandler = null)
        {
            //See #264 - the collection inability to cast has no amorphous data so it MUST throw
            //used only for collections inner calls
            if (v == null)
            {
                return(null);
            }

            var customHandler = fieldCustomHandler ?? JsonHandlerAttribute.TryFind(toType);

            if (customHandler != null)
            {
                var castResult = customHandler.TypeCastOnRead(v, toType, fromUI, options);

                if (castResult.Outcome >= JsonHandlerAttribute.TypeCastOutcome.ChangedTargetType)
                {
                    toType = castResult.ToType;
                }

                if (castResult.Outcome == JsonHandlerAttribute.TypeCastOutcome.ChangedSourceValue)
                {
                    v = castResult.Value;
                }
                else if (castResult.Outcome == JsonHandlerAttribute.TypeCastOutcome.HandledCast)
                {
                    return(castResult.Value);
                }
            }

            //object goes as is
            if (toType == typeof(object))
            {
                return(v);
            }

            //IJSONDataObject
            if (toType == typeof(IJsonDataObject))
            {
                if (v is IJsonDataObject)
                {
                    return(v);     //goes as is
                }
                if (v is string s) //string containing embedded JSON
                {
                    var jo = s.JsonToDataObject();
                    return(jo);
                }
            }

            //IJSONDataMap
            if (toType == typeof(JsonDataMap))
            {
                if (v is JsonDataMap)
                {
                    return(v);     //goes as is
                }
                if (v is string s) //string containing embedded JSON
                {
                    var jo = s.JsonToDataObject() as JsonDataMap;
                    return(jo);
                }
            }

            //IJSONDataArray
            if (toType == typeof(JsonDataArray))
            {
                if (v is JsonDataArray)
                {
                    return(v);     //goes as is
                }
                if (v is string s) //string containing embedded JSON
                {
                    var jo = s.JsonToDataObject() as JsonDataArray;
                    return(jo);
                }
            }

            var nntp = toType;

            if (nntp.IsGenericType && nntp.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                nntp = toType.GetGenericArguments()[0];
            }

            //20191217 DKh
            if (nntp == typeof(DateTime))
            {
                if (options.LocalDates)
                {
                    var d = v.AsDateTime(System.Globalization.DateTimeStyles.AssumeLocal);
                    return(d);
                }
                else //UTC (the default)
                {
                    var d = v.AsDateTime(System.Globalization.DateTimeStyles.AssumeUniversal | System.Globalization.DateTimeStyles.AdjustToUniversal);
                    return(d);
                }
            }
            //20191217 DKh


            //Custom JSON Readable (including config)
            if (typeof(IJsonReadable).IsAssignableFrom(nntp) || typeof(IConfigSectionNode).IsAssignableFrom(nntp))
            {
                var toAllocate = nntp;

                //Configuration requires special handling because nodes do not exist as independent entities and there
                //is master/detail relationship between them
                if (toAllocate == typeof(Configuration) ||
                    toAllocate == typeof(ConfigSectionNode) ||
                    toAllocate == typeof(IConfigSectionNode))
                {
                    toAllocate = typeof(MemoryConfiguration);
                }

                if (toAllocate.IsAbstract)
                {
                    throw new JSONDeserializationException(StringConsts.JSON_DESERIALIZATION_ABSTRACT_TYPE_ERROR.Args(toAllocate.Name, nameof(JsonHandlerAttribute)));
                }

                var newval = SerializationUtils.MakeNewObjectInstance(toAllocate) as IJsonReadable;
                var got    = newval.ReadAsJson(v, fromUI, options);//this may re-allocate the result based of newval

                if (!got.match)
                {
                    return(null);
                }

                if (typeof(IConfigSectionNode).IsAssignableFrom(nntp))
                {
                    return((got.self as Configuration)?.Root);
                }

                return(got.self);
            }

            //byte[] direct assignment w/o copies
            if (nntp == typeof(byte[]) && v is byte[] passed)
            {
                return(passed);
            }


            //field def = []
            if (toType.IsArray)
            {
                var fvseq = v as IEnumerable;
                if (fvseq == null)
                {
                    return(null);      //can not set non enumerable into array
                }
                var arr    = fvseq.Cast <object>().Select(e => cast(e, toType.GetElementType(), fromUI, options, fieldCustomHandler)).ToArray();
                var newval = Array.CreateInstance(toType.GetElementType(), arr.Length);
                for (var i = 0; i < newval.Length; i++)
                {
                    newval.SetValue(arr[i], i);
                }

                return(newval);
            }

            //field def = List<t>
            if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(List <>))
            {
                var fvseq = v as IEnumerable;
                if (fvseq == null)
                {
                    return(false);      //can not set non enumerable into List<t>
                }
                var arr    = fvseq.Cast <object>().Select(e => cast(e, toType.GetGenericArguments()[0], fromUI, options, fieldCustomHandler)).ToArray();
                var newval = SerializationUtils.MakeNewObjectInstance(toType) as IList;
                for (var i = 0; i < arr.Length; i++)
                {
                    newval.Add(arr[i]);
                }

                return(newval);
            }

            //last resort
            try
            {
                return(StringValueConversion.AsType(v.ToString(), toType, false));
            }
            catch
            {
                return(null);//the value could not be converted, and is going to go into amorphous bag if it is enabled
            }
        }