private fsResult InternalDeserialize_4_Cycles(Type overrideConverterType, fsData data, Type resultType, ref object result) { if (IsObjectDefinition(data)) { // NOTE: object references are handled at stage 1 // If this is a definition, then we have a serialization invariant that this is the // first time we have encountered the object (TODO: verify in the deserialization logic) // Since at this stage in the deserialization process we already have access to the // object instance, so we just need to sync the object id to the references database // so that when we encounter the instance we lookup this same object. We want to do // this before actually deserializing the object because when deserializing the object // there may be references to itself. int sourceId = int.Parse(data.AsDictionary[Key_ObjectDefinition].AsString); _references.AddReferenceWithId(sourceId, result); } // Nothing special, go through the standard deserialization logic. return(InternalDeserialize_5_Converter(overrideConverterType, data, resultType, ref result)); }
//... fsResult Internal_Deserialize(fsData data, Type storageType, ref object result, Type overrideConverterType) { //$ref encountered. Do before inheritance. if (IsObjectReference(data)) { int refId = int.Parse(data.AsDictionary[KEY_OBJECT_REFERENCE].AsString); result = _references.GetReferenceObject(refId); return(fsResult.Success); } var deserializeResult = fsResult.Success; var objectType = result != null?result.GetType() : storageType; Type forwardMigrationPreviousType = null; // Gather processors and call OnBeforeDeserialize before anything var processors = GetProcessors(objectType); Invoke_OnBeforeDeserialize(processors, objectType, ref data); // If the serialized state contains type information, then we need to make sure to update our // objectType and data to the proper values so that when we construct an object instance later // and run deserialization we run it on the proper type. // $type if (IsTypeSpecified(data)) { var typeNameData = data.AsDictionary[KEY_INSTANCE_TYPE]; do { if (!typeNameData.IsString) { deserializeResult.AddMessage(string.Format("{0} value must be a string", KEY_INSTANCE_TYPE)); break; } var typeName = typeNameData.AsString; var type = ReflectionTools.GetType(typeName, storageType); if (type == null) { deserializeResult.AddMessage(string.Format("{0} type can not be resolved", typeName)); break; } var migrateAtt = type.RTGetAttribute <fsMigrateToAttribute>(true); if (migrateAtt != null) { // if migrating from another type, save the original type and mutate the current type if (!typeof(IMigratable).IsAssignableFrom(migrateAtt.targetType)) { throw new Exception("TargetType of [fsMigrateToAttribute] must implement IMigratable<T> with T being the target type"); } forwardMigrationPreviousType = type; if (type.IsGenericType && migrateAtt.targetType.IsGenericTypeDefinition) { type = migrateAtt.targetType.MakeGenericType(type.GetGenericArguments()); } else { type = migrateAtt.targetType; } } if (!storageType.IsAssignableFrom(type)) { deserializeResult.AddMessage(string.Format("Ignoring type specifier. Field or type {0} can't hold and instance of type {1}", storageType, type)); break; } objectType = type; } while (false); } var converter = GetConverter(objectType, overrideConverterType); if (converter == null) { return(fsResult.Warn(string.Format("No Converter available for {0}", objectType))); } // Construct an object instance if we don't have one already using actual objectType if (ReferenceEquals(result, null) || result.GetType() != objectType) { result = converter.CreateInstance(data, objectType); } // if migrating from another type, do migration now. if (forwardMigrationPreviousType != null) { //we deserialize versioning first on the old model type and then do migration var previousInstance = GetConverter(forwardMigrationPreviousType, null).CreateInstance(data, forwardMigrationPreviousType); TryDeserializeVersioning(ref previousInstance, ref data); TryDeserializeMigration(ref result, ref data, forwardMigrationPreviousType, previousInstance); } else { // if not a forward migration, try deserialize versioning as normal TryDeserializeVersioning(ref result, ref data); } // invoke callback with objectType Invoke_OnBeforeDeserializeAfterInstanceCreation(processors, objectType, result, ref data); // $id if (IsObjectDefinition(data)) { var sourceId = int.Parse(data.AsDictionary[KEY_OBJECT_DEFINITION].AsString); _references.AddReferenceWithId(sourceId, result); } // $content if (IsWrappedData(data)) { data = data.AsDictionary[KEY_CONTENT]; } // push collector TryPush(result); // must pass actual objectType deserializeResult += converter.TryDeserialize(data, ref result, objectType); if (deserializeResult.Succeeded) { Invoke_OnAfterDeserialize(processors, objectType, result); } // pop collector TryPop(result); return(deserializeResult); }
//... fsResult Internal_Deserialize(Type overrideConverterType, fsData data, Type storageType, ref object result, out List <fsObjectProcessor> processors) { //$ref encountered. Do before inheritance. if (IsObjectReference(data)) { int refId = int.Parse(data.AsDictionary[KEY_OBJECT_REFERENCE].AsString); result = _references.GetReferenceObject(refId); processors = GetProcessors(result.GetType()); return(fsResult.Success); } var deserializeResult = fsResult.Success; // We wait until here to actually Invoke_OnBeforeDeserialize because we do not // have the correct set of processors to invoke until *after* we have resolved // the proper type to use for deserialization. processors = GetProcessors(storageType); Invoke_OnBeforeDeserialize(processors, storageType, ref data); var objectType = storageType; // If the serialized state contains type information, then we need to make sure to update our // objectType and data to the proper values so that when we construct an object instance later // and run deserialization we run it on the proper type. // $type if (IsTypeSpecified(data)) { var typeNameData = data.AsDictionary[KEY_INSTANCE_TYPE]; do { if (!typeNameData.IsString) { deserializeResult.AddMessage(string.Format("{0} value must be a string", KEY_INSTANCE_TYPE)); break; } var typeName = typeNameData.AsString; var type = ReflectionTools.GetType(typeName, storageType); if (type == null) { deserializeResult.AddMessage(string.Format("{0} type can not be resolved", typeName)); break; } if (!storageType.IsAssignableFrom(type)) { deserializeResult.AddMessage(string.Format("Ignoring type specifier. Field or type {0} can't hold and instance of type {1}", storageType, type)); break; } objectType = type; } while (false); } var converter = GetConverter(objectType, overrideConverterType); if (converter == null) { return(fsResult.Warn(string.Format("No Converter available for {0}", objectType))); } // Construct an object instance if we don't have one already using actual objectType if (ReferenceEquals(result, null) || result.GetType() != objectType) { result = converter.CreateInstance(data, objectType); } // invoke callback with storageType Invoke_OnBeforeDeserializeAfterInstanceCreation(processors, storageType, result, ref data); // $id if (IsObjectDefinition(data)) { var sourceId = int.Parse(data.AsDictionary[KEY_OBJECT_DEFINITION].AsString); _references.AddReferenceWithId(sourceId, result); } // $content if (IsWrappedData(data)) { data = data.AsDictionary[KEY_CONTENT]; } // must pass actual objectType instead of storageType return(deserializeResult += converter.TryDeserialize(data, ref result, objectType)); }