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
}//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 } }
private static void toDoc(Doc doc, DocReadOptions options, JsonDataMap jsonMap, ref string field, bool fromUI) { var amorph = doc as IAmorphousData; var schema = doc.Schema; foreach (var mfld in jsonMap) { field = mfld.Key; var fv = mfld.Value; //Multi-targeting for deserialization to TypedDoc from JSON Schema.FieldDef def; if (options.BindBy == DocReadOptions.By.CodeName) { def = schema[field]; } else { def = schema.TryFindFieldByTargetedBackendName(options.TargetName, field);//what about case sensitive json name? } //No such field exists in a typed doc, try to put in amorphous data if (def == null) { if (amorph != null) { if (amorph.AmorphousDataEnabled) { amorph.AmorphousData[mfld.Key] = fv; } } continue; } if (fromUI && def.NonUI) { continue; //skip NonUI fields } //weed out NULLS here if (fv == null) { doc.SetFieldValue(def, null); continue; } //fv is NEVER NULL here var wasset = setOneField(doc, def, fv, fromUI, options); //<------------------- field assignment //try to put in amorphous data if could not be set in a field if (!wasset && amorph != null) { if (amorph.AmorphousDataEnabled) { amorph.AmorphousData[mfld.Key] = fv; } } }//foreach field in jsonMap //process FORM var form = doc as Form; if (form != null) { form.FormMode = jsonMap[Form.JSON_MODE_PROPERTY].AsEnum <FormMode>(FormMode.Unspecified); form.CSRFToken = jsonMap[Form.JSON_CSRF_PROPERTY].AsString(); var roundtrip = jsonMap[Form.JSON_ROUNDTRIP_PROPERTY].AsString(); if (roundtrip.IsNotNullOrWhiteSpace()) { form.SetRoundtripBagFromJSONString(roundtrip); } } if (amorph != null && amorph.AmorphousDataEnabled) { amorph.AfterLoad(options.TargetName ?? "json"); } }