/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using MongoDB.Bson.Serialization.Options; namespace MongoDB.Bson.Serialization.Serializers { /// /// Represents a serializer for Interfaces. /// /// The type of the interface. /// The type of the implementation. public class ImpliedImplementationInterfaceSerializer : SerializerBase, IBsonArraySerializer, IBsonDictionarySerializer, IBsonDocumentSerializer, IChildSerializerConfigurable where TImplementation : class, TInterface { // private fields private readonly Lazy> _lazyImplementationSerializer; // constructors /// /// Initializes a new instance of the class. /// public ImpliedImplementationInterfaceSerializer() : this(BsonSerializer.SerializerRegistry) { } /// /// Initializes a new instance of the class. /// /// The implementation serializer. public ImpliedImplementationInterfaceSerializer(IBsonSerializer implementationSerializer) : this(new Lazy>(() => implementationSerializer)) { if (implementationSerializer == null) { throw new ArgumentNullException("implementationSerializer"); } } /// /// Initializes a new instance of the class. /// /// The serializer registry. public ImpliedImplementationInterfaceSerializer(IBsonSerializerRegistry serializerRegistry) : this(new Lazy>(() => serializerRegistry.GetSerializer())) { if (serializerRegistry == null) { throw new ArgumentNullException("serializerRegistry"); } } private ImpliedImplementationInterfaceSerializer(Lazy> lazyImplementationSerializer) { var interfaceTypeInfo = typeof(TInterface).GetTypeInfo(); if (!interfaceTypeInfo.IsInterface) { var message = string.Format("{0} is not an interface.", typeof(TInterface).FullName); throw new ArgumentException(message, ""); } _lazyImplementationSerializer = lazyImplementationSerializer; } // public properties /// /// Gets the dictionary representation. /// /// /// The dictionary representation. /// /// public DictionaryRepresentation DictionaryRepresentation { get { var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer; if (dictionarySerializer != null) { return dictionarySerializer.DictionaryRepresentation; } var message = string.Format( "{0} does not have a DictionaryRepresentation.", BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType())); throw new NotSupportedException(message); } } /// /// Gets the key serializer. /// /// /// The key serializer. /// /// public IBsonSerializer KeySerializer { get { var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer; if (dictionarySerializer != null) { return dictionarySerializer.KeySerializer; } var message = string.Format( "{0} does not have a KeySerializer.", BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType())); throw new NotSupportedException(message); } } /// /// Gets the implementation serializer. /// /// /// The implementation serializer. /// public IBsonSerializer ImplementationSerializer { get { return _lazyImplementationSerializer.Value; } } /// /// Gets the value serializer. /// /// /// The value serializer. /// /// public IBsonSerializer ValueSerializer { get { var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer; if (dictionarySerializer != null) { return dictionarySerializer.ValueSerializer; } var message = string.Format( "{0} does not have a ValueSerializer.", BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType())); throw new NotSupportedException(message); } } // public methods /// /// Deserializes a value. /// /// The deserialization context. /// The deserialization args. /// A deserialized value. /// public override TInterface Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var bsonReader = context.Reader; if (bsonReader.GetCurrentBsonType() == BsonType.Null) { bsonReader.ReadNull(); return default(TInterface); } else { return _lazyImplementationSerializer.Value.Deserialize(context); } } /// /// Tries to get the serialization info for the individual items of the array. /// /// The serialization information. /// /// true if the serialization info exists; otherwise false. /// public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo) { var arraySerializer = _lazyImplementationSerializer.Value as IBsonArraySerializer; if (arraySerializer != null) { return arraySerializer.TryGetItemSerializationInfo(out serializationInfo); } serializationInfo = null; return false; } /// /// Tries to get the serialization info for a member. /// /// Name of the member. /// The serialization information. /// /// true if the serialization info exists; otherwise false. /// public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo) { var documentSerializer = _lazyImplementationSerializer.Value as IBsonDocumentSerializer; if (documentSerializer != null) { return documentSerializer.TryGetMemberSerializationInfo(memberName, out serializationInfo); } serializationInfo = null; return false; } /// /// Serializes a value. /// /// The serialization context. /// The serialization args. /// The document. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TInterface value) { var bsonWriter = context.Writer; if (value == null) { bsonWriter.WriteNull(); } else { var actualType = value.GetType(); if (actualType == typeof(TImplementation)) { _lazyImplementationSerializer.Value.Serialize(context, (TImplementation)value); } else { var serializer = BsonSerializer.LookupSerializer(actualType); serializer.Serialize(context, value); } } } /// /// Returns a serializer that has been reconfigured with the specified implementation serializer. /// /// The implementation serializer. /// /// The reconfigured serializer. /// public ImpliedImplementationInterfaceSerializer WithImplementationSerializer(IBsonSerializer implementationSerializer) { if (implementationSerializer == ImplementationSerializer) { return this; } else { return new ImpliedImplementationInterfaceSerializer(implementationSerializer); } } // explicit interface implementations IBsonSerializer IChildSerializerConfigurable.ChildSerializer { get { return ImplementationSerializer; } } IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer) { return WithImplementationSerializer((IBsonSerializer)childSerializer); } } }