private static void toRow(Row row, JSONDataMap jsonMap, ref string field, bool fromUI) { var amorph = row as IAmorphousData; foreach (var mfld in jsonMap) { var fv = mfld.Value; var rfd = row.Schema[mfld.Key]; field = mfld.Key; if (rfd == null) { if (amorph != null) { if (amorph.AmorphousDataEnabled) { amorph.AmorphousData[mfld.Key] = fv; } } continue; } if (fromUI && rfd.NonUI) { continue; //skip NonUI fields } if (fv == null) { row.SetFieldValue(rfd, null); } else if (fv is JSONDataMap) { if (typeof(TypedRow).IsAssignableFrom(rfd.Type)) { row.SetFieldValue(rfd, ToRow(rfd.Type, (JSONDataMap)fv)); } else { row.SetFieldValue(rfd, fv); //try to set row's field to MAP directly } } else if (rfd.NonNullableType == typeof(TimeSpan) && (fv is ulong || fv is long || fv is int || fv is uint)) { var lt = Convert.ToInt64(fv); row.SetFieldValue(rfd, TimeSpan.FromTicks(lt)); } else if (fv is int || fv is long || fv is ulong || fv is double || fv is bool) { row.SetFieldValue(rfd, fv); } else if (fv is byte[] && rfd.Type == typeof(byte[])) //optimization byte array assignment without copies { var passed = (byte[])fv; var arr = new byte[passed.Length]; Array.Copy(passed, arr, passed.Length); row.SetFieldValue(rfd, arr); } else if (fv is JSONDataArray || fv.GetType().IsArray) { JSONDataArray arr; if (fv is JSONDataArray) { arr = (JSONDataArray)fv; } else { arr = new JSONDataArray(((Array)fv).Length); foreach (var elm in (System.Collections.IEnumerable)fv) { arr.Add(elm); } } if (rfd.Type.IsArray) { var raet = rfd.Type.GetElementType(); //row array element type if (typeof(TypedRow).IsAssignableFrom(raet)) { var narr = Array.CreateInstance(raet, arr.Count); for (var i = 0; i < narr.Length; i++) { narr.SetValue(ToRow(raet, arr[i] as JSONDataMap), i); } row.SetFieldValue(rfd, narr); } //else primitives else { var narr = Array.CreateInstance(raet, arr.Count); for (var i = 0; i < narr.Length; i++) { if (arr[i] != null) { narr.SetValue(StringValueConversion.AsType(arr[i].ToString(), raet, false), i); } } row.SetFieldValue(rfd, narr); } } else if (rfd.Type.IsGenericType && rfd.Type.GetGenericTypeDefinition() == typeof(List <>)) //List { var gat = rfd.Type.GetGenericArguments()[0]; var lst = Activator.CreateInstance(rfd.Type) as System.Collections.IList; if (typeof(TypedRow).IsAssignableFrom(gat)) { for (var i = 0; i < arr.Count; i++) { if (arr[i] is JSONDataMap) { lst.Add(ToRow(gat, arr[i] as JSONDataMap)); } else { lst.Add(null); } } } else if (gat == typeof(object)) { for (var i = 0; i < arr.Count; i++) { lst.Add(arr[i]); } } else if (gat == typeof(string)) { for (var i = 0; i < arr.Count; i++) { if (arr[i] != null) { lst.Add(arr[i].ToString()); } else { lst.Add(null); } } } else if (gat.IsPrimitive || gat == typeof(NFX.DataAccess.Distributed.GDID) || gat == typeof(Guid) || gat == typeof(DateTime)) { for (var i = 0; i < arr.Count; i++) { if (arr[i] != null) { lst.Add(StringValueConversion.AsType(arr[i].ToString(), gat, false)); } } } else if (gat.IsGenericType && gat.GetGenericTypeDefinition() == typeof(Nullable <>)) { var nt = gat.GetGenericArguments()[0]; if (nt.IsPrimitive || nt == typeof(NFX.DataAccess.Distributed.GDID) || nt == typeof(Guid) || nt == typeof(DateTime)) { for (var i = 0; i < arr.Count; i++) { if (arr[i] != null) { lst.Add(StringValueConversion.AsType(arr[i].ToString(), gat, false)); } else { lst.Add(null); } } } } row.SetFieldValue(rfd, lst); } } else { //Try to get String containing JSON if (fv is string) { var sfv = (string)fv; if (rfd.Type == typeof(string)) { row.SetFieldValue(rfd, sfv); continue; } if (typeof(TypedRow).IsAssignableFrom(rfd.Type)) { if (sfv.IsNotNullOrWhiteSpace()) { row.SetFieldValue(rfd, ToRow(rfd.Type, (JSONDataMap)deserializeObject(read(sfv)))); } continue; } if (typeof(IJSONDataObject).IsAssignableFrom(rfd.Type)) { if (sfv.IsNotNullOrWhiteSpace()) { row.SetFieldValue(rfd, deserializeObject(read(sfv))); //try to set row's field to MAP directly } continue; } } row.SetFieldValue(rfd, StringValueConversion.AsType(fv.ToString(), rfd.Type, false)); //<--Type conversion } } //foreach //20140914 DKh var form = row as FormModel; if (form != null) { form.FormMode = jsonMap[FormModel.JSON_MODE_PROPERTY].AsEnum <FormMode>(FormMode.Unspecified); form.CSRFToken = jsonMap[FormModel.JSON_CSRF_PROPERTY].AsString(); var roundtrip = jsonMap[FormModel.JSON_ROUNDTRIP_PROPERTY].AsString(); if (roundtrip.IsNotNullOrWhiteSpace()) { form.SetRoundtripBagFromJSONString(roundtrip); } } if (amorph != null && amorph.AmorphousDataEnabled) { amorph.AfterLoad("json"); } }
}//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 } }
}//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, NameBinding nameBinding) { //used only for collections inner calls if (v == null) { return(null); } //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 (toType.IsGenericType && nntp.GetGenericTypeDefinition() == typeof(Nullable <>)) { nntp = toType.GetGenericArguments()[0]; } //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); } var newval = SerializationUtils.MakeNewObjectInstance(toAllocate) as IJsonReadable; var got = newval.ReadAsJson(v, fromUI, nameBinding);//this me 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 <object>; if (fvseq == null) { return(null); //can not set non enumerable into array } var arr = fvseq.Select(e => cast(e, toType.GetElementType(), fromUI, nameBinding)).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 <object>; if (fvseq == null) { return(false); //can not set non enumerable into List<t> } var arr = fvseq.Select(e => cast(e, toType.GetGenericArguments()[0], fromUI, nameBinding)).ToArray(); var newval = SerializationUtils.MakeNewObjectInstance(toType) as System.Collections.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 } }