Manager which is responsible for discovering what fields and properties of an object should be serialized.
Inheritance: ISerializationManager
            public void ReturnsCorrectFields()
            {
                var serializationManager = new SerializationManager();

                var fieldsToSerialize = serializationManager.GetFieldsToSerialize(typeof(TestModel)).ToArray();

                Assert.AreEqual(1, fieldsToSerialize.Length);
                Assert.AreEqual("_includedField", fieldsToSerialize[0]);
            }
示例#2
0
            public void ReturnsCorrectProperties()
            {
                var serializationManager = new SerializationManager();

                var propertiesToSerialize = serializationManager.GetRegularPropertiesToSerialize(typeof(TestModel)).ToArray();

                Assert.AreEqual(1, propertiesToSerialize.Length);
                Assert.AreEqual("IncludedRegularProperty", propertiesToSerialize[0].Key);
            }
            public void ReturnsRightModifiersInRightOrderForInheritedClasses()
            {
                var serializationManager = new SerializationManager();

                var modifiers = serializationManager.GetSerializerModifiers(typeof(TestModels.ModelC));

                Assert.AreEqual(3, modifiers.Length);
                Assert.AreEqual(typeof(TestModels.ModelASerializerModifier), modifiers[0].GetType());
                Assert.AreEqual(typeof(TestModels.ModelBSerializerModifier), modifiers[1].GetType());
                Assert.AreEqual(typeof(TestModels.ModelCSerializerModifier), modifiers[2].GetType());
            }
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var fields = serializationManager.GetFields(typeof(TestModel)).ToArray();

                Assert.AreEqual(1, fields.Length);
                Assert.AreEqual("_includedField", fields[0].Key);
                Assert.AreEqual(SerializationMemberGroup.Field, fields[0].Value.MemberGroup);
            }
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var properties = serializationManager.GetRegularProperties(typeof(TestModel)).ToArray();

                Assert.AreEqual(1, properties.Length);
                Assert.AreEqual("IncludedRegularProperty", properties[0].Key);
                Assert.AreEqual(SerializationMemberGroup.RegularProperty, properties[0].Value.MemberGroup);
            }
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var properties = serializationManager.GetCatelProperties(typeof(TestModel)).ToArray();

                Assert.AreEqual(3, properties.Length);
                Assert.AreEqual("IncludedCatelProperty", properties[0].Key);
                Assert.AreEqual(SerializationMemberGroup.CatelProperty, properties[0].Value.MemberGroup);

                Assert.AreEqual("ExcludedCatelProperty", properties[1].Key);
                Assert.AreEqual(SerializationMemberGroup.CatelProperty, properties[1].Value.MemberGroup);

                Assert.AreEqual("ExcludedProtectedCatelProperty", properties[2].Key);
                Assert.AreEqual(SerializationMemberGroup.CatelProperty, properties[2].Value.MemberGroup);
            }
            public void SerializesModelsWithParsableObjectsAndSerializerModifierNotUsingParse()
            {
                var originalObject = new TestModelWithParsableMembersWithoutAttributes();
                originalObject.Vector = new Vector(1, 2, 3);

                var serializationManager = new SerializationManager();
                serializationManager.AddSerializerModifier<TestModelWithParsableMembersWithoutAttributes, TestModelWithParsableMembersNotUsingParseSerializerModifier>();

                TestSerializationOnAllSerializers((serializer, config, description) =>
                {
                    var clonedObject = SerializationTestHelper.SerializeAndDeserialize(originalObject, serializer, config);

                    Assert.IsFalse(clonedObject.Vector.UsedParse);
                    Assert.AreEqual(originalObject.Vector.X, clonedObject.Vector.X, description);
                    Assert.AreEqual(originalObject.Vector.Y, clonedObject.Vector.Y, description);
                    Assert.AreEqual(originalObject.Vector.Z, clonedObject.Vector.Z, description);
                }, serializationManager: serializationManager);
            }
示例#8
0
        /// <summary>
        /// Gets the serializable members for the specified model.
        /// </summary>
        /// <param name="context">The serialization context.</param>
        /// <param name="model">The model.</param>
        /// <param name="membersToIgnore">The members to ignore.</param>
        /// <returns>The list of members to serialize.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="model"/> is <c>null</c>.</exception>
        public virtual List <MemberValue> GetSerializableMembers(ISerializationContext <TSerializationContextInfo> context, object model, params string[] membersToIgnore)
        {
            Argument.IsNotNull("model", model);

            var listToSerialize        = new List <MemberValue>();
            var membersToIgnoreHashSet = new HashSet <string>(membersToIgnore);

            var modelType = model.GetType();

            // If a basic type, we need to directly deserialize as member and replace the context model
            if (ShouldExternalSerializerHandleMember(context.ModelType))
            {
                listToSerialize.Add(new MemberValue(SerializationMemberGroup.SimpleRootObject, modelType, modelType, RootObjectName, RootObjectName, model));
                return(listToSerialize);
            }

            if (ShouldSerializeAsDictionary(modelType))
            {
                listToSerialize.Add(new MemberValue(SerializationMemberGroup.Dictionary, modelType, modelType, CollectionName, CollectionName, model));
                return(listToSerialize);
            }

            if (ShouldSerializeAsCollection(modelType))
            {
                listToSerialize.Add(new MemberValue(SerializationMemberGroup.Collection, modelType, modelType, CollectionName, CollectionName, model));
                return(listToSerialize);
            }

            if (modelType == typeof(SerializableKeyValuePair))
            {
                var keyValuePair = (SerializableKeyValuePair)model;

                var keyType   = typeof(object);
                var valueType = typeof(object);

                // Search max 2 levels deep, if not found, then we failed
                var parentDictionary = context.FindParentType(x => x.IsDictionary(), 2);
                if (parentDictionary != null)
                {
                    var genericTypeDefinition = parentDictionary.GetGenericArgumentsEx();

                    keyType   = genericTypeDefinition[0];
                    valueType = genericTypeDefinition[1];
                }

                listToSerialize.Add(new MemberValue(SerializationMemberGroup.RegularProperty, modelType, keyType, "Key", "Key", keyValuePair.Key));
                listToSerialize.Add(new MemberValue(SerializationMemberGroup.RegularProperty, modelType, valueType, "Value", "Value", keyValuePair.Value));

                return(listToSerialize);
            }

            var modelInfo = _serializationModelCache.GetFromCacheOrFetch(modelType, () =>
            {
                var catelProperties = SerializationManager.GetCatelPropertiesToSerialize(modelType);
                var fields          = SerializationManager.GetFieldsToSerialize(modelType);
                var properties      = SerializationManager.GetRegularPropertiesToSerialize(modelType);

                return(new SerializationModelInfo(modelType, catelProperties, fields, properties));
            });

            var members = new List <MemberMetadata>();

            members.AddRange(modelInfo.CatelPropertiesByName.Values);
            members.AddRange(modelInfo.PropertiesByName.Values);
            members.AddRange(modelInfo.FieldsByName.Values);

            foreach (var memberMetadata in members)
            {
                var memberName = memberMetadata.MemberName;
                if (membersToIgnoreHashSet.Contains(memberName) || ShouldIgnoreMember(model, memberName))
                {
                    Log.Debug("Member '{0}' is being ignored for serialization", memberName);
                    continue;
                }

                var memberValue = ObjectAdapter.GetMemberValue(model, memberName, modelInfo);
                if (memberValue != null)
                {
                    listToSerialize.Add(memberValue);
                }
            }

            return(listToSerialize);
        }
示例#9
0
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var fields = serializationManager.GetFieldNames(typeof(TestModel)).ToArray();

                Assert.AreEqual(2, fields.Length);
                Assert.AreEqual("_excludedField", fields[0]);
                Assert.AreEqual("_includedField", fields[1]);
            }
示例#10
0
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var properties = serializationManager.GetRegularPropertyNames(typeof(TestModel)).ToArray();

                Assert.AreEqual(2, properties.Length);
                Assert.AreEqual("ExcludedRegularProperty", properties[0]);
                Assert.AreEqual("IncludedRegularProperty", properties[1]);
            }
示例#11
0
            public void ReturnsCorrectValue()
            {
                var serializationManager = new SerializationManager();

                var properties = serializationManager.GetCatelPropertyNames(typeof(TestModel)).ToArray();

                Assert.AreEqual(4, properties.Length);

                Assert.AreEqual("DateTimeProperty", properties[0]);
                Assert.AreEqual("IncludedCatelProperty", properties[1]);
                Assert.AreEqual("ExcludedCatelProperty", properties[2]);
                Assert.AreEqual("ExcludedProtectedCatelProperty", properties[3]);
            }
        /// <summary>
        /// Deserializes the members.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns>The deserialized list of member values.</returns>
        protected virtual List <MemberValue> DeserializeMembers(ISerializationContext <TSerializationContextInfo> context)
        {
            ApiCop.UpdateRule <InitializationApiCopRule>("SerializerBase.WarmupAtStartup",
                                                         x => x.SetInitializationMode(InitializationMode.Lazy, GetType().GetSafeFullName(false)));

            var deserializedMemberValues = new List <MemberValue>();

            var serializerModifiers = SerializationManager.GetSerializerModifiers(context.ModelType).Reverse();

            var membersToDeserialize = GetSerializableMembers(context, context.Model);

            foreach (var member in membersToDeserialize)
            {
                var memberSerializationEventArgs = new MemberSerializationEventArgs(context, member);

                DeserializingMember.SafeInvoke(this, memberSerializationEventArgs);

                BeforeDeserializeMember(context, member);

                var serializationObject = DeserializeMember(context, member);
                if (serializationObject.IsSuccessful)
                {
                    // Note that we need to sync the member values every time
                    var memberValue = new MemberValue(member.MemberGroup, member.ModelType, member.MemberType, member.Name,
                                                      member.NameForSerialization, serializationObject.MemberValue);

                    if (memberValue.MemberGroup == SerializationMemberGroup.Dictionary)
                    {
                        var targetDictionary = TypeFactory.CreateInstance(member.MemberType) as IDictionary;
                        if (targetDictionary == null)
                        {
                            throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a dictionary, but target model cannot be updated because it does not implement IDictionary",
                                                                                      context.ModelTypeName);
                        }

                        var enumerable = memberValue.Value as List <SerializableKeyValuePair>;
                        if (enumerable != null)
                        {
                            foreach (var item in enumerable)
                            {
                                targetDictionary.Add(item.Key, item.Value);
                            }
                        }
                        else
                        {
                            var sourceDictionary = memberValue.Value as IDictionary;
                            if (sourceDictionary != null)
                            {
                                foreach (var key in sourceDictionary.Keys)
                                {
                                    targetDictionary.Add(key, sourceDictionary[key]);
                                }
                            }
                        }

                        member.Value = targetDictionary;
                    }
                    else if (memberValue.MemberGroup == SerializationMemberGroup.Collection)
                    {
                        var sourceCollection = memberValue.Value as IEnumerable;

                        if (member.MemberType.IsArrayEx())
                        {
                            var elementType = member.MemberType.GetElementTypeEx();
                            member.Value = sourceCollection.ToArray(elementType);
                        }
                        else
                        {
                            var targetCollection = TypeFactory.CreateInstance(member.MemberType) as IList;
                            if (targetCollection == null)
                            {
                                throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a collection, but target model cannot be updated because it does not implement IList",
                                                                                          context.ModelTypeName);
                            }

                            if (sourceCollection != null)
                            {
                                foreach (var item in sourceCollection)
                                {
                                    targetCollection.Add(item);
                                }
                            }

                            member.Value = targetCollection;
                        }
                    }
                    else
                    {
                        member.Value = memberValue.Value;
                    }

                    deserializedMemberValues.Add(memberValue);

                    foreach (var serializerModifier in serializerModifiers)
                    {
                        serializerModifier.DeserializeMember(context, member);
                        memberValue.Value = member.Value;
                    }

                    AfterDeserializeMember(context, member);
                    memberValue.Value = member.Value;

                    DeserializedMember.SafeInvoke(this, memberSerializationEventArgs);
                    memberValue.Value = member.Value;
                }
            }

            if (deserializedMemberValues.Count > 0)
            {
                var firstMember = deserializedMemberValues[0];
                if (firstMember.MemberGroup == SerializationMemberGroup.SimpleRootObject)
                {
                    // Completely replace root object (this is a basic (non-reference) type)
                    context.Model = firstMember.Value;
                }
                else if (firstMember.MemberGroup == SerializationMemberGroup.Dictionary)
                {
                    var targetDictionary = context.Model as IDictionary;
                    if (targetDictionary == null)
                    {
                        throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a dictionary, but target model cannot be updated because it does not implement IDictionary",
                                                                                  context.ModelTypeName);
                    }

                    targetDictionary.Clear();

                    var sourceDictionary = firstMember.Value as IDictionary;
                    if (sourceDictionary != null)
                    {
                        foreach (var key in sourceDictionary.Keys)
                        {
                            targetDictionary.Add(key, sourceDictionary[key]);
                        }
                    }
                }
                else if (firstMember.MemberGroup == SerializationMemberGroup.Collection)
                {
                    if (context.ModelType.IsArrayEx())
                    {
                        context.Model = firstMember.Value;
                    }
                    else
                    {
                        var targetCollection = context.Model as IList;
                        if (targetCollection == null)
                        {
                            throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a collection, but target model cannot be updated because it does not implement IList",
                                                                                      context.ModelTypeName);
                        }

                        targetCollection.Clear();

                        var sourceCollection = firstMember.Value as IEnumerable;
                        if (sourceCollection != null)
                        {
                            foreach (var item in sourceCollection)
                            {
                                targetCollection.Add(item);
                            }
                        }
                    }
                }
                else
                {
                    PopulateModel(context.Model, deserializedMemberValues.ToArray());
                }
            }

            return(deserializedMemberValues);
        }
示例#13
0
        /// <summary>
        /// Returns whether the member value should be serialized using <c>ToString(IFormatProvider)</c> and deserialized using <c>Parse(string, IFormatProvider)</c>.
        /// </summary>
        /// <param name="memberValue">The member value.</param>
        /// <param name="checkActualMemberType">if set to <c>true</c>, check the actual member type.</param>
        /// <returns>
        ///   <c>true</c> if the member should be serialized using parse.
        /// </returns>
        protected virtual bool ShouldSerializeUsingParseAndToString(MemberValue memberValue, bool checkActualMemberType)
        {
            var cacheKey = $"{memberValue.ModelTypeName}|{memberValue.Name}|{checkActualMemberType}";

            return(_shouldSerializeUsingParseCache.GetFromCacheOrFetch(cacheKey, () =>
            {
                var serializerModifiers = SerializationManager.GetSerializerModifiers(memberValue.ModelType);

                var useParseAndToString = false;

                var fieldInfo = memberValue.ModelType.GetFieldEx(memberValue.Name);
                if (fieldInfo != null)
                {
                    useParseAndToString = fieldInfo.IsDecoratedWithAttribute <SerializeUsingParseAndToStringAttribute>();
                }

                if (!useParseAndToString)
                {
                    var propertyInfo = memberValue.ModelType.GetPropertyEx(memberValue.Name);
                    if (propertyInfo != null)
                    {
                        useParseAndToString = propertyInfo.IsDecoratedWithAttribute <SerializeUsingParseAndToStringAttribute>();
                    }
                }

                // Note: serializer modifiers can always win
                foreach (var serializerModifier in serializerModifiers)
                {
                    var value = serializerModifier.ShouldSerializeMemberUsingParse(memberValue);
                    if (value.HasValue)
                    {
                        if (!value.Value)
                        {
                            return false;
                        }

                        // At least 1 serializer modifier wants this to be using parse and tostring
                        useParseAndToString = true;
                    }
                }

                if (!useParseAndToString)
                {
                    return false;
                }

                var memberType = checkActualMemberType ? memberValue.ActualMemberType : memberValue.MemberType;
                if (memberType is null)
                {
                    memberType = memberValue.MemberType;
                }

                var toStringMethod = GetObjectToStringMethod(memberType);
                if (toStringMethod is null)
                {
                    return false;
                }

                var parseMethod = GetObjectParseMethod(memberType);
                if (parseMethod is null)
                {
                    return false;
                }

                return true;
            }));
        }
示例#14
0
        /// <summary>
        /// Populates the model with the specified members.
        /// </summary>
        /// <param name="context">The serialization context.</param>
        /// <param name="members">The members.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="context"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="members"/> is <c>null</c>.</exception>
        protected virtual void PopulateModel(ISerializationContext <TSerializationContextInfo> context, List <MemberValue> members)
        {
            Argument.IsNotNull("model", context);
            Argument.IsNotNull("members", members);

            if (members.Count > 0)
            {
                var firstMember = members[0];
                if (firstMember.MemberGroup == SerializationMemberGroup.SimpleRootObject)
                {
                    // Completely replace root object (this is a basic (non-reference) type)
                    context.Model = firstMember.Value;
                }
                else if (firstMember.MemberGroup == SerializationMemberGroup.Dictionary)
                {
                    var targetDictionary = context.Model as IDictionary;
                    if (targetDictionary is null)
                    {
                        throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a dictionary, but target model cannot be updated because it does not implement IDictionary",
                                                                                  context.ModelTypeName);
                    }

                    targetDictionary.Clear();

                    var sourceDictionary = firstMember.Value as IDictionary;
                    if (sourceDictionary != null)
                    {
                        foreach (var key in sourceDictionary.Keys)
                        {
                            targetDictionary.Add(key, sourceDictionary[key]);
                        }
                    }
                }
                else if (firstMember.MemberGroup == SerializationMemberGroup.Collection)
                {
                    if (context.ModelType.IsArrayEx())
                    {
                        context.Model = firstMember.Value;
                    }
                    else
                    {
                        var targetCollection = context.Model as IList;
                        if (targetCollection is null)
                        {
                            throw Log.ErrorAndCreateException <NotSupportedException>("'{0}' seems to be a collection, but target model cannot be updated because it does not implement IList",
                                                                                      context.ModelTypeName);
                        }

                        targetCollection.Clear();

                        var sourceCollection = firstMember.Value as IEnumerable;
                        if (sourceCollection != null)
                        {
                            foreach (var item in sourceCollection)
                            {
                                targetCollection.Add(item);
                            }
                        }
                    }
                }
                else
                {
                    // Populate using properties
                    var model     = context.Model;
                    var modelType = context.ModelType;

                    var modelInfo = _serializationModelCache.GetFromCacheOrFetch(modelType, () =>
                    {
                        var catelProperties   = SerializationManager.GetCatelProperties(modelType);
                        var fields            = SerializationManager.GetFields(modelType);
                        var regularProperties = SerializationManager.GetRegularProperties(modelType);

                        return(new SerializationModelInfo(modelType, catelProperties, fields, regularProperties));
                    });

                    foreach (var member in members)
                    {
                        ObjectAdapter.SetMemberValue(model, member, modelInfo);
                    }
                }
            }
        }
示例#15
0
            public void ThrowsArgumentNullExceptionForNullType()
            {
                var serializationManager = new SerializationManager();

                ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => serializationManager.RemoveSerializerModifier(null, typeof(DynamicSerializerModifier)));
                ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => serializationManager.RemoveSerializerModifier(typeof(DynamicSerializerModifierModel), null));
            }
            public void ThrowsArgumentNullExceptionForNullType()
            {
                var serializationManager = new SerializationManager();

                ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => serializationManager.GetFieldsToSerialize(null));
            }
示例#17
0
            public void RemovesSerializerModifier()
            {
                var serializationManager = new SerializationManager();

                serializationManager.AddSerializerModifier<DynamicSerializerModifierModel, DynamicSerializerModifier>();

                var modifiers = serializationManager.GetSerializerModifiers(typeof(DynamicSerializerModifierModel));

                Assert.AreEqual(1, modifiers.Length);
                Assert.AreEqual(typeof(DynamicSerializerModifier), modifiers[0].GetType());

                serializationManager.RemoveSerializerModifier<DynamicSerializerModifierModel, DynamicSerializerModifier>();

                modifiers = serializationManager.GetSerializerModifiers(typeof(DynamicSerializerModifierModel));

                Assert.AreEqual(0, modifiers.Length);
            }
            public void ThrowsArgumentNullExceptionForNullType()
            {
                var serializationManager = new SerializationManager();

                ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => serializationManager.GetCatelPropertyNames(null));
            }
示例#19
0
        private static void TestSerializationOnAllSerializers(Action<ISerializer, ISerializationConfiguration, string> action, 
            bool testWithoutGraphIdsAsWell = true, ISerializationManager serializationManager = null)
        {
            if (serializationManager == null)
            {
                serializationManager = new SerializationManager();
            }

            var serializerConfigurations = new Dictionary<Type, List<ISerializationConfiguration>>();

            serializerConfigurations[typeof(XmlSerializer)] = new List<ISerializationConfiguration>(new[]
            {
                new SerializationConfiguration()
            });

            serializerConfigurations[typeof(BinarySerializer)] = new List<ISerializationConfiguration>(new[]
            {
                new SerializationConfiguration()
            });

            serializerConfigurations[typeof(JsonSerializer)] = new List<ISerializationConfiguration>(new[]
            {
                new JsonSerializationConfiguration
                {
                    UseBson = false
                },
                new JsonSerializationConfiguration
                {
                    UseBson = true
                },
            });

            var serializers = new List<ISerializer>();

            serializers.Add(SerializationTestHelper.GetXmlSerializer(XmlSerializerOptimalizationMode.Performance, serializationManager));
            serializers.Add(SerializationTestHelper.GetXmlSerializer(XmlSerializerOptimalizationMode.PrettyXml, serializationManager));
            serializers.Add(SerializationTestHelper.GetBinarySerializer(serializationManager));
            serializers.Add(SerializationTestHelper.GetJsonSerializer(serializationManager));

            if (testWithoutGraphIdsAsWell)
            {
                var basicJsonSerializer = SerializationTestHelper.GetJsonSerializer(serializationManager);
                basicJsonSerializer.PreserveReferences = false;
                basicJsonSerializer.WriteTypeInfo = false;
                serializers.Add(basicJsonSerializer);
            }

            foreach (var serializer in serializers)
            {
                var type = serializer.GetType();
                var typeName = type.GetSafeFullName(false);

                var configurations = serializerConfigurations[type];
                foreach (var configuration in configurations)
                {
                    Log.Info();
                    Log.Info();
                    Log.Info();
                    Log.Info("=== TESTING SERIALIZER: {0} ===", typeName);
                    Log.Info();
                    Log.Info();
                    Log.Info();

                    action(serializer, configuration, typeName);
                }
            }
        }