private void DeserializeMember(BsonReader bsonReader, object obj, BsonMemberMap memberMap)
 {
     try
     {
         var  nominalType = memberMap.MemberType;
         Type actualType;
         if (bsonReader.CurrentBsonType == BsonType.Null)
         {
             actualType = nominalType;
         }
         else
         {
             var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
             actualType = discriminatorConvention.GetActualType(bsonReader, nominalType); // returns nominalType if no discriminator found
         }
         var serializer = memberMap.GetSerializer(actualType);
         var value      = serializer.Deserialize(bsonReader, nominalType, actualType, memberMap.SerializationOptions);
         memberMap.Setter(obj, value);
     }
     catch (Exception ex)
     {
         var message = string.Format(
             "An error occurred while deserializing the {0} {1} of class {2}: {3}", // terminating period provided by nested message
             memberMap.MemberName, (memberMap.MemberInfo.MemberType == MemberTypes.Field) ? "field" : "property", obj.GetType().FullName, ex.Message);
         throw new FileFormatException(message, ex);
     }
 }
Пример #2
0
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public object Deserialize(
            BsonReader bsonReader,
            Type nominalType,
            IBsonSerializationOptions options
            )
        {
            VerifyNominalType(nominalType);
            if (bsonReader.CurrentBsonType == Bson.BsonType.Null)
            {
                bsonReader.ReadNull();
                return(null);
            }
            else
            {
                var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                var actualType = discriminatorConvention.GetActualType(bsonReader, nominalType);
                if (actualType != nominalType)
                {
                    var serializer = BsonSerializer.LookupSerializer(actualType);
                    if (serializer != this)
                    {
                        // in rare cases a concrete actualType might have a more specialized serializer
                        return(serializer.Deserialize(bsonReader, nominalType, actualType, options));
                    }
                }

                return(Deserialize(bsonReader, nominalType, actualType, options));
            }
        }
Пример #3
0
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public static object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
        {
            if (nominalType == typeof(BsonDocument))
            {
                var bsonDocument = new BsonDocument();
                return(bsonDocument.Deserialize(bsonReader, nominalType, options));
            }

            // if nominalType is an interface find out the actualType and use it instead
            if (nominalType.IsInterface)
            {
                var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                var actualType = discriminatorConvention.GetActualType(bsonReader, nominalType);
                if (actualType == nominalType)
                {
                    var message = string.Format("Unable to determine actual type of object to deserialize. NominalType is the interface {0}.", nominalType);
                    throw new FileFormatException(message);
                }
                var serializer = LookupSerializer(actualType);
                return(serializer.Deserialize(bsonReader, actualType, options));
            }
            else
            {
                var serializer = LookupSerializer(nominalType);
                return(serializer.Deserialize(bsonReader, nominalType, options));
            }
        }
        /// <summary>
        /// Looks up the discriminator convention for a type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>A discriminator convention.</returns>
        public static IDiscriminatorConvention LookupDiscriminatorConvention(
            Type type
            )
        {
            lock (BsonSerializer.ConfigLock) {
                IDiscriminatorConvention convention;
                if (!discriminatorConventions.TryGetValue(type, out convention))
                {
                    // if there is no convention registered for object register the default one
                    if (!discriminatorConventions.ContainsKey(typeof(object)))
                    {
                        var defaultDiscriminatorConvention = StandardDiscriminatorConvention.Hierarchical;
                        discriminatorConventions.Add(typeof(object), defaultDiscriminatorConvention);
                        if (type == typeof(object))
                        {
                            return(defaultDiscriminatorConvention);
                        }
                    }

                    if (type.IsInterface)
                    {
                        // TODO: should convention for interfaces be inherited from parent interfaces?
                        convention = discriminatorConventions[typeof(object)];
                        discriminatorConventions[type] = convention;
                    }
                    else
                    {
                        // inherit the discriminator convention from the closest parent that has one
                        Type parentType = type.BaseType;
                        while (convention == null)
                        {
                            if (parentType == null)
                            {
                                var message = string.Format("No discriminator convention found for type {0}.", type.FullName);
                                throw new BsonSerializationException(message);
                            }
                            if (discriminatorConventions.TryGetValue(parentType, out convention))
                            {
                                break;
                            }
                            parentType = parentType.BaseType;
                        }

                        // register this convention for all types between this and the parent type where we found the convention
                        var unregisteredType = type;
                        while (unregisteredType != parentType)
                        {
                            BsonDefaultSerializer.RegisterDiscriminatorConvention(unregisteredType, convention);
                            unregisteredType = unregisteredType.BaseType;
                        }
                    }
                }
                return(convention);
            }
        }
        // internal methods
        /// <summary>
        /// Gets the discriminator convention for the member type.
        /// </summary>
        /// <returns>The discriminator convention for the member type.</returns>
        internal IDiscriminatorConvention GetDiscriminatorConvention()
        {
            // return a cached discriminator convention when possible
            var discriminatorConvention = _cachedDiscriminatorConvention;

            if (discriminatorConvention == null)
            {
                // it's possible but harmless for multiple threads to do the initial lookup at the same time
                discriminatorConvention        = BsonDefaultSerializer.LookupDiscriminatorConvention(_memberType);
                _cachedDiscriminatorConvention = discriminatorConvention;
            }
            return(discriminatorConvention);
        }
Пример #6
0
        private void DeserializeMember(
            BsonReader bsonReader,
            object obj,
            BsonMemberMap memberMap
            )
        {
            var  nominalType = memberMap.MemberType;
            Type actualType;

            if (bsonReader.CurrentBsonType == BsonType.Null)
            {
                actualType = nominalType;
            }
            else
            {
                var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                actualType = discriminatorConvention.GetActualType(bsonReader, nominalType); // returns nominalType if no discriminator found
            }
            var serializer = memberMap.GetSerializer(actualType);
            var value      = serializer.Deserialize(bsonReader, nominalType, actualType, memberMap.SerializationOptions);

            memberMap.Setter(obj, value);
        }
Пример #7
0
        /// <summary>
        /// Serializes an object to a BsonWriter.
        /// </summary>
        /// <param name="bsonWriter">The BsonWriter.</param>
        /// <param name="nominalType">The nominal type.</param>
        /// <param name="value">The object.</param>
        /// <param name="options">The serialization options.</param>
        public void Serialize(
            BsonWriter bsonWriter,
            Type nominalType,
            object value,
            IBsonSerializationOptions options
            )
        {
            if (value == null)
            {
                bsonWriter.WriteNull();
            }
            else
            {
                // Nullable types are weird because they get boxed as their underlying value type
                // we can best handle that by switching the nominalType to the underlying value type
                // (so VerifyNominalType doesn't fail and we don't get an unnecessary discriminator)
                if (nominalType.IsGenericType && nominalType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    nominalType = nominalType.GetGenericArguments()[0];
                }

                VerifyNominalType(nominalType);
                var actualType = (value == null) ? nominalType : value.GetType();
                var classMap   = BsonClassMap.LookupClassMap(actualType);

                bsonWriter.WriteStartDocument();
                var           documentOptions = (options == null) ? DocumentSerializationOptions.Defaults : (DocumentSerializationOptions)options;
                BsonMemberMap idMemberMap     = null;
                if (documentOptions.SerializeIdFirst)
                {
                    idMemberMap = classMap.IdMemberMap;
                    if (idMemberMap != null)
                    {
                        SerializeMember(bsonWriter, value, idMemberMap);
                    }
                }

                if (actualType != nominalType || classMap.DiscriminatorIsRequired || classMap.HasRootClass)
                {
                    // never write out a discriminator for an anonymous class
                    if (!classMap.IsAnonymous)
                    {
                        var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                        var discriminator           = discriminatorConvention.GetDiscriminator(nominalType, actualType);
                        if (discriminator != null)
                        {
                            bsonWriter.WriteName(discriminatorConvention.ElementName);
                            discriminator.WriteTo(bsonWriter);
                        }
                    }
                }

                foreach (var memberMap in classMap.MemberMaps)
                {
                    // note: if serializeIdFirst is false then idMemberMap will be null (so no property will be skipped)
                    if (memberMap != idMemberMap)
                    {
                        if (memberMap == classMap.ExtraElementsMemberMap)
                        {
                            SerializeExtraElements(bsonWriter, value, memberMap);
                        }
                        else
                        {
                            SerializeMember(bsonWriter, value, memberMap);
                        }
                    }
                }
                bsonWriter.WriteEndDocument();
            }
        }
Пример #8
0
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="actualType">The actual type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public object Deserialize(
            BsonReader bsonReader,
            Type nominalType,
            Type actualType,
            IBsonSerializationOptions options
            )
        {
            VerifyNominalType(nominalType);
            if (bsonReader.CurrentBsonType == Bson.BsonType.Null)
            {
                bsonReader.ReadNull();
                return(null);
            }
            else
            {
                if (actualType.IsValueType)
                {
                    var message = string.Format("Value class {0} cannot be deserialized.", actualType.FullName);
                    throw new BsonSerializationException(message);
                }

                var classMap = BsonClassMap.LookupClassMap(actualType);
                if (classMap.IsAnonymous)
                {
                    throw new InvalidOperationException("An anonymous class cannot be deserialized.");
                }
                var obj = classMap.CreateInstance();

                bsonReader.ReadStartDocument();
                var missingElementMemberMaps = new HashSet <BsonMemberMap>(classMap.MemberMaps); // make a copy!
                var discriminatorConvention  = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    var elementName = bsonReader.ReadName();
                    if (elementName == discriminatorConvention.ElementName)
                    {
                        bsonReader.SkipValue(); // skip over discriminator
                        continue;
                    }

                    var memberMap = classMap.GetMemberMapForElement(elementName);
                    if (memberMap != null && memberMap != classMap.ExtraElementsMemberMap)
                    {
                        DeserializeMember(bsonReader, obj, memberMap);
                        missingElementMemberMaps.Remove(memberMap);
                    }
                    else
                    {
                        if (classMap.ExtraElementsMemberMap != null)
                        {
                            DeserializeExtraElement(bsonReader, obj, elementName, classMap.ExtraElementsMemberMap);
                        }
                        else if (classMap.IgnoreExtraElements)
                        {
                            bsonReader.SkipValue();
                        }
                        else
                        {
                            var message = string.Format("Element '{0}' does not match any field or property of class {1}.", elementName, classMap.ClassType.FullName);
                            throw new FileFormatException(message);
                        }
                    }
                }
                bsonReader.ReadEndDocument();

                foreach (var memberMap in missingElementMemberMaps)
                {
                    if (memberMap.IsRequired)
                    {
                        var fieldOrProperty = (memberMap.MemberInfo.MemberType == MemberTypes.Field) ? "field" : "property";
                        var message         = string.Format("Required element '{0}' for {1} '{2}' of class {3} is missing.", memberMap.ElementName, fieldOrProperty, memberMap.MemberName, classMap.ClassType.FullName);
                        throw new FileFormatException(message);
                    }

                    if (memberMap.HasDefaultValue)
                    {
                        memberMap.ApplyDefaultValue(obj);
                    }
                }

                return(obj);
            }
        }
Пример #9
0
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="actualType">The actual type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public object Deserialize(
            BsonReader bsonReader,
            Type nominalType,
            Type actualType,
            IBsonSerializationOptions options
            )
        {
            VerifyNominalType(nominalType);
            if (bsonReader.CurrentBsonType == Bson.BsonType.Null)
            {
                bsonReader.ReadNull();
                return(null);
            }
            else
            {
                var classMap = BsonClassMap.LookupClassMap(actualType);
                if (classMap.IsAnonymous)
                {
                    throw new InvalidOperationException("Anonymous classes cannot be deserialized");
                }
                var obj = classMap.CreateInstance();

                bsonReader.ReadStartDocument();
                var missingElementMemberMaps = new HashSet <BsonMemberMap>(classMap.MemberMaps); // make a copy!
                var discriminatorConvention  = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    var elementName = bsonReader.ReadName();
                    if (elementName == discriminatorConvention.ElementName)
                    {
                        bsonReader.SkipValue(); // skip over discriminator
                        continue;
                    }

                    var memberMap = classMap.GetMemberMapForElement(elementName);
                    if (memberMap != null && memberMap != classMap.ExtraElementsMemberMap)
                    {
                        DeserializeMember(bsonReader, obj, memberMap);
                        missingElementMemberMaps.Remove(memberMap);
                    }
                    else
                    {
                        if (classMap.ExtraElementsMemberMap != null)
                        {
                            DeserializeExtraElement(bsonReader, obj, elementName, classMap.ExtraElementsMemberMap);
                        }
                        else if (classMap.IgnoreExtraElements)
                        {
                            bsonReader.SkipValue();
                        }
                        else
                        {
                            string message = string.Format("Unexpected element: {0}", elementName);
                            throw new FileFormatException(message);
                        }
                    }
                }
                bsonReader.ReadEndDocument();

                foreach (var memberMap in missingElementMemberMaps)
                {
                    if (memberMap.IsRequired)
                    {
                        var message = string.Format("Required element is missing: {0}", memberMap.ElementName);
                        throw new FileFormatException(message);
                    }

                    if (memberMap.HasDefaultValue)
                    {
                        memberMap.ApplyDefaultValue(obj);
                    }
                }

                return(obj);
            }
        }