/* Copyright 2010-2016 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.Concurrent; using System.Reflection; namespace MongoDB.Bson.Serialization { /// /// Default, global implementation of an . /// public sealed class BsonSerializerRegistry : IBsonSerializerRegistry { // private fields private readonly ConcurrentDictionary _cache; private readonly ConcurrentStack _serializationProviders; // constructors /// /// Initializes a new instance of the class. /// public BsonSerializerRegistry() { _cache = new ConcurrentDictionary(); _serializationProviders = new ConcurrentStack(); } // public methods /// /// Gets the serializer for the specified . /// /// The type. /// /// The serializer. /// public IBsonSerializer GetSerializer(Type type) { if (type == null) { throw new ArgumentNullException("type"); } var typeInfo = type.GetTypeInfo(); if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters) { var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type)); throw new ArgumentException(message, "type"); } return _cache.GetOrAdd(type, CreateSerializer); } /// /// Gets the serializer for the specified . /// /// /// /// The serializer. /// public IBsonSerializer GetSerializer() { return (IBsonSerializer)GetSerializer(typeof(T)); } /// /// Registers the serializer. /// /// The type. /// The serializer. public void RegisterSerializer(Type type, IBsonSerializer serializer) { if (type == null) { throw new ArgumentNullException("type"); } if (serializer == null) { throw new ArgumentNullException("serializer"); } var typeInfo = type.GetTypeInfo(); if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type)) { var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type)); throw new BsonSerializationException(message); } if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters) { var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type)); throw new ArgumentException(message, "type"); } if (!_cache.TryAdd(type, serializer)) { var message = string.Format("There is already a serializer registered for type {0}.", BsonUtils.GetFriendlyTypeName(type)); throw new BsonSerializationException(message); } } /// /// Registers the serialization provider. This behaves like a stack, so the /// last provider registered is the first provider consulted. /// /// The serialization provider. public void RegisterSerializationProvider(IBsonSerializationProvider serializationProvider) { if (serializationProvider == null) { throw new ArgumentNullException("serializationProvider"); } _serializationProviders.Push(serializationProvider); } // private methods private IBsonSerializer CreateSerializer(Type type) { foreach (var serializationProvider in _serializationProviders) { IBsonSerializer serializer; var registryAwareSerializationProvider = serializationProvider as IRegistryAwareBsonSerializationProvider; if (registryAwareSerializationProvider != null) { serializer = registryAwareSerializationProvider.GetSerializer(type, this); } else { serializer = serializationProvider.GetSerializer(type); } if (serializer != null) { return serializer; } } var message = string.Format("No serializer found for type {0}.", type.FullName); throw new BsonSerializationException(message); } } }