BsonSerializer.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /* Copyright 2010-2014 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.IO;
  18. using System.Threading;
  19. // don't add using statement for MongoDB.Bson.Serialization.Serializers to minimize dependencies on DefaultSerializer
  20. using MongoDB.Bson.IO;
  21. using MongoDB.Bson.Serialization.Attributes;
  22. using MongoDB.Bson.Serialization.Conventions;
  23. using MongoDB.Bson.Serialization.IdGenerators;
  24. using MongoDB.Bson.Serialization.Serializers;
  25. namespace MongoDB.Bson.Serialization
  26. {
  27. /// <summary>
  28. /// A static class that represents the BSON serialization functionality.
  29. /// </summary>
  30. public static class BsonSerializer
  31. {
  32. // private static fields
  33. private static ReaderWriterLock __configLock = new ReaderWriterLock();
  34. private static Dictionary<Type, IIdGenerator> __idGenerators = new Dictionary<Type, IIdGenerator>();
  35. private static Dictionary<Type, IBsonSerializer> __serializers = new Dictionary<Type, IBsonSerializer>();
  36. private static Dictionary<Type, Type> __genericSerializerDefinitions = new Dictionary<Type, Type>();
  37. private static List<IBsonSerializationProvider> __serializationProviders = new List<IBsonSerializationProvider>();
  38. private static Dictionary<Type, IDiscriminatorConvention> __discriminatorConventions = new Dictionary<Type, IDiscriminatorConvention>();
  39. private static Dictionary<BsonValue, HashSet<Type>> __discriminators = new Dictionary<BsonValue, HashSet<Type>>();
  40. private static HashSet<Type> __discriminatedTypes = new HashSet<Type>();
  41. private static HashSet<Type> __typesWithRegisteredKnownTypes = new HashSet<Type>();
  42. private static bool __useNullIdChecker = false;
  43. private static bool __useZeroIdChecker = false;
  44. // static constructor
  45. static BsonSerializer()
  46. {
  47. RegisterDefaultSerializationProviders();
  48. RegisterIdGenerators();
  49. }
  50. // public static properties
  51. /// <summary>
  52. /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
  53. /// </summary>
  54. public static bool UseNullIdChecker
  55. {
  56. get { return __useNullIdChecker; }
  57. set { __useNullIdChecker = value; }
  58. }
  59. /// <summary>
  60. /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered.
  61. /// </summary>
  62. public static bool UseZeroIdChecker
  63. {
  64. get { return __useZeroIdChecker; }
  65. set { __useZeroIdChecker = value; }
  66. }
  67. // internal static properties
  68. internal static ReaderWriterLock ConfigLock
  69. {
  70. get { return __configLock; }
  71. }
  72. // public static methods
  73. /// <summary>
  74. /// Deserializes an object from a BsonDocument.
  75. /// </summary>
  76. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  77. /// <param name="document">The BsonDocument.</param>
  78. /// <returns>A TNominalType.</returns>
  79. public static TNominalType Deserialize<TNominalType>(BsonDocument document)
  80. {
  81. return (TNominalType)Deserialize(document, typeof(TNominalType));
  82. }
  83. /// <summary>
  84. /// Deserializes an object from a JsonBuffer.
  85. /// </summary>
  86. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  87. /// <param name="buffer">The JsonBuffer.</param>
  88. /// <returns>A TNominalType.</returns>
  89. public static TNominalType Deserialize<TNominalType>(JsonBuffer buffer)
  90. {
  91. return (TNominalType)Deserialize(buffer, typeof(TNominalType));
  92. }
  93. /// <summary>
  94. /// Deserializes an object from a BsonReader.
  95. /// </summary>
  96. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  97. /// <param name="bsonReader">The BsonReader.</param>
  98. /// <returns>A TNominalType.</returns>
  99. public static TNominalType Deserialize<TNominalType>(BsonReader bsonReader)
  100. {
  101. return (TNominalType)Deserialize(bsonReader, typeof(TNominalType));
  102. }
  103. /// <summary>
  104. /// Deserializes an object from a BSON byte array.
  105. /// </summary>
  106. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  107. /// <param name="bytes">The BSON byte array.</param>
  108. /// <returns>A TNominalType.</returns>
  109. public static TNominalType Deserialize<TNominalType>(byte[] bytes)
  110. {
  111. return (TNominalType)Deserialize(bytes, typeof(TNominalType));
  112. }
  113. /// <summary>
  114. /// Deserializes an object from a BSON Stream.
  115. /// </summary>
  116. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  117. /// <param name="stream">The BSON Stream.</param>
  118. /// <returns>A TNominalType.</returns>
  119. public static TNominalType Deserialize<TNominalType>(Stream stream)
  120. {
  121. return (TNominalType)Deserialize(stream, typeof(TNominalType));
  122. }
  123. /// <summary>
  124. /// Deserializes an object from a JSON string.
  125. /// </summary>
  126. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  127. /// <param name="json">The JSON string.</param>
  128. /// <returns>A TNominalType.</returns>
  129. public static TNominalType Deserialize<TNominalType>(string json)
  130. {
  131. return (TNominalType)Deserialize(json, typeof(TNominalType));
  132. }
  133. /// <summary>
  134. /// Deserializes an object from a JSON TextReader.
  135. /// </summary>
  136. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  137. /// <param name="textReader">The JSON TextReader.</param>
  138. /// <returns>A TNominalType.</returns>
  139. public static TNominalType Deserialize<TNominalType>(TextReader textReader)
  140. {
  141. return (TNominalType)Deserialize(textReader, typeof(TNominalType));
  142. }
  143. /// <summary>
  144. /// Deserializes an object from a BsonDocument.
  145. /// </summary>
  146. /// <param name="document">The BsonDocument.</param>
  147. /// <param name="nominalType">The nominal type of the object.</param>
  148. /// <returns>A TNominalType.</returns>
  149. public static object Deserialize(BsonDocument document, Type nominalType)
  150. {
  151. using (var bsonReader = BsonReader.Create(document))
  152. {
  153. return Deserialize(bsonReader, nominalType);
  154. }
  155. }
  156. /// <summary>
  157. /// Deserializes an object from a JsonBuffer.
  158. /// </summary>
  159. /// <param name="buffer">The JsonBuffer.</param>
  160. /// <param name="nominalType">The nominal type of the object.</param>
  161. /// <returns>An object.</returns>
  162. public static object Deserialize(JsonBuffer buffer, Type nominalType)
  163. {
  164. using (var bsonReader = BsonReader.Create(buffer))
  165. {
  166. return Deserialize(bsonReader, nominalType);
  167. }
  168. }
  169. /// <summary>
  170. /// Deserializes an object from a BsonReader.
  171. /// </summary>
  172. /// <param name="bsonReader">The BsonReader.</param>
  173. /// <param name="nominalType">The nominal type of the object.</param>
  174. /// <returns>An object.</returns>
  175. public static object Deserialize(BsonReader bsonReader, Type nominalType)
  176. {
  177. return Deserialize(bsonReader, nominalType, null);
  178. }
  179. /// <summary>
  180. /// Deserializes an object from a BsonReader.
  181. /// </summary>
  182. /// <param name="bsonReader">The BsonReader.</param>
  183. /// <param name="nominalType">The nominal type of the object.</param>
  184. /// <param name="options">The serialization options.</param>
  185. /// <returns>An object.</returns>
  186. public static object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
  187. {
  188. // if nominalType is an interface find out the actualType and use it instead
  189. if (nominalType.IsInterface)
  190. {
  191. var discriminatorConvention = LookupDiscriminatorConvention(nominalType);
  192. var actualType = discriminatorConvention.GetActualType(bsonReader, nominalType);
  193. if (actualType == nominalType)
  194. {
  195. var message = string.Format("Unable to determine actual type of object to deserialize. NominalType is the interface {0}.", nominalType);
  196. throw new Exception(message);
  197. }
  198. var serializer = LookupSerializer(actualType);
  199. return serializer.Deserialize(bsonReader, actualType, options);
  200. }
  201. else
  202. {
  203. var serializer = LookupSerializer(nominalType);
  204. return serializer.Deserialize(bsonReader, nominalType, options);
  205. }
  206. }
  207. /// <summary>
  208. /// Deserializes an object from a BSON byte array.
  209. /// </summary>
  210. /// <param name="bytes">The BSON byte array.</param>
  211. /// <param name="nominalType">The nominal type of the object.</param>
  212. /// <returns>An object.</returns>
  213. public static object Deserialize(byte[] bytes, Type nominalType)
  214. {
  215. using (var memoryStream = new MemoryStream(bytes))
  216. {
  217. return Deserialize(memoryStream, nominalType);
  218. }
  219. }
  220. /// <summary>
  221. /// Deserializes an object from a BSON Stream.
  222. /// </summary>
  223. /// <param name="stream">The BSON Stream.</param>
  224. /// <param name="nominalType">The nominal type of the object.</param>
  225. /// <returns>An object.</returns>
  226. public static object Deserialize(Stream stream, Type nominalType)
  227. {
  228. using (var bsonReader = BsonReader.Create(stream))
  229. {
  230. return Deserialize(bsonReader, nominalType);
  231. }
  232. }
  233. /// <summary>
  234. /// Deserializes an object from a JSON string.
  235. /// </summary>
  236. /// <param name="json">The JSON string.</param>
  237. /// <param name="nominalType">The nominal type of the object.</param>
  238. /// <returns>An object.</returns>
  239. public static object Deserialize(string json, Type nominalType)
  240. {
  241. using (var bsonReader = BsonReader.Create(json))
  242. {
  243. return Deserialize(bsonReader, nominalType);
  244. }
  245. }
  246. /// <summary>
  247. /// Deserializes an object from a JSON TextReader.
  248. /// </summary>
  249. /// <param name="textReader">The JSON TextReader.</param>
  250. /// <param name="nominalType">The nominal type of the object.</param>
  251. /// <returns>An object.</returns>
  252. public static object Deserialize(TextReader textReader, Type nominalType)
  253. {
  254. using (var bsonReader = BsonReader.Create(textReader))
  255. {
  256. return Deserialize(bsonReader, nominalType);
  257. }
  258. }
  259. /// <summary>
  260. /// Returns whether the given type has any discriminators registered for any of its subclasses.
  261. /// </summary>
  262. /// <param name="type">A Type.</param>
  263. /// <returns>True if the type is discriminated.</returns>
  264. public static bool IsTypeDiscriminated(Type type)
  265. {
  266. return type.IsInterface || __discriminatedTypes.Contains(type);
  267. }
  268. /// <summary>
  269. /// Looks up the actual type of an object to be deserialized.
  270. /// </summary>
  271. /// <param name="nominalType">The nominal type of the object.</param>
  272. /// <param name="discriminator">The discriminator.</param>
  273. /// <returns>The actual type of the object.</returns>
  274. public static Type LookupActualType(Type nominalType, BsonValue discriminator)
  275. {
  276. if (discriminator == null)
  277. {
  278. return nominalType;
  279. }
  280. // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
  281. EnsureKnownTypesAreRegistered(nominalType);
  282. __configLock.EnterReadLock();
  283. try
  284. {
  285. Type actualType = null;
  286. HashSet<Type> hashSet;
  287. if (__discriminators.TryGetValue(discriminator, out hashSet))
  288. {
  289. foreach (var type in hashSet)
  290. {
  291. if (nominalType.IsAssignableFrom(type))
  292. {
  293. if (actualType == null)
  294. {
  295. actualType = type;
  296. }
  297. else
  298. {
  299. string message = string.Format("Ambiguous discriminator '{0}'.", discriminator);
  300. throw new BsonSerializationException(message);
  301. }
  302. }
  303. }
  304. }
  305. if (actualType == null && discriminator.IsString)
  306. {
  307. actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name
  308. }
  309. if (actualType == null)
  310. {
  311. string message = string.Format("Unknown discriminator value '{0}'.", discriminator);
  312. throw new BsonSerializationException(message);
  313. }
  314. if (!nominalType.IsAssignableFrom(actualType))
  315. {
  316. string message = string.Format(
  317. "Actual type {0} is not assignable to expected type {1}.",
  318. actualType.FullName, nominalType.FullName);
  319. throw new BsonSerializationException(message);
  320. }
  321. return actualType;
  322. }
  323. finally
  324. {
  325. __configLock.ExitReadLock();
  326. }
  327. }
  328. /// <summary>
  329. /// Looks up the discriminator convention for a type.
  330. /// </summary>
  331. /// <param name="type">The type.</param>
  332. /// <returns>A discriminator convention.</returns>
  333. public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
  334. {
  335. __configLock.EnterReadLock();
  336. try
  337. {
  338. IDiscriminatorConvention convention;
  339. if (__discriminatorConventions.TryGetValue(type, out convention))
  340. {
  341. return convention;
  342. }
  343. }
  344. finally
  345. {
  346. __configLock.ExitReadLock();
  347. }
  348. __configLock.EnterWriteLock();
  349. try
  350. {
  351. IDiscriminatorConvention convention;
  352. if (!__discriminatorConventions.TryGetValue(type, out convention))
  353. {
  354. // if there is no convention registered for object register the default one
  355. if (!__discriminatorConventions.ContainsKey(typeof(object)))
  356. {
  357. var defaultDiscriminatorConvention = StandardDiscriminatorConvention.Hierarchical;
  358. __discriminatorConventions.Add(typeof(object), defaultDiscriminatorConvention);
  359. if (type == typeof(object))
  360. {
  361. return defaultDiscriminatorConvention;
  362. }
  363. }
  364. if (type.IsInterface)
  365. {
  366. // TODO: should convention for interfaces be inherited from parent interfaces?
  367. convention = __discriminatorConventions[typeof(object)];
  368. __discriminatorConventions[type] = convention;
  369. }
  370. else
  371. {
  372. // inherit the discriminator convention from the closest parent that has one
  373. Type parentType = type.BaseType;
  374. while (convention == null)
  375. {
  376. if (parentType == null)
  377. {
  378. var message = string.Format("No discriminator convention found for type {0}.", type.FullName);
  379. throw new BsonSerializationException(message);
  380. }
  381. if (__discriminatorConventions.TryGetValue(parentType, out convention))
  382. {
  383. break;
  384. }
  385. parentType = parentType.BaseType;
  386. }
  387. // register this convention for all types between this and the parent type where we found the convention
  388. var unregisteredType = type;
  389. while (unregisteredType != parentType)
  390. {
  391. RegisterDiscriminatorConvention(unregisteredType, convention);
  392. unregisteredType = unregisteredType.BaseType;
  393. }
  394. }
  395. }
  396. return convention;
  397. }
  398. finally
  399. {
  400. __configLock.ExitWriteLock();
  401. }
  402. }
  403. /// <summary>
  404. /// Looks up a generic serializer definition.
  405. /// </summary>
  406. /// <param name="genericTypeDefinition">The generic type.</param>
  407. /// <returns>A generic serializer definition.</returns>
  408. public static Type LookupGenericSerializerDefinition(Type genericTypeDefinition)
  409. {
  410. __configLock.EnterReadLock();
  411. try
  412. {
  413. Type genericSerializerDefinition;
  414. __genericSerializerDefinitions.TryGetValue(genericTypeDefinition, out genericSerializerDefinition);
  415. return genericSerializerDefinition;
  416. }
  417. finally
  418. {
  419. __configLock.ExitReadLock();
  420. }
  421. }
  422. /// <summary>
  423. /// Looks up an IdGenerator.
  424. /// </summary>
  425. /// <param name="type">The Id type.</param>
  426. /// <returns>An IdGenerator for the Id type.</returns>
  427. public static IIdGenerator LookupIdGenerator(Type type)
  428. {
  429. __configLock.EnterReadLock();
  430. try
  431. {
  432. IIdGenerator idGenerator;
  433. if (__idGenerators.TryGetValue(type, out idGenerator))
  434. {
  435. return idGenerator;
  436. }
  437. }
  438. finally
  439. {
  440. __configLock.ExitReadLock();
  441. }
  442. __configLock.EnterWriteLock();
  443. try
  444. {
  445. IIdGenerator idGenerator;
  446. if (!__idGenerators.TryGetValue(type, out idGenerator))
  447. {
  448. if (type.IsValueType && __useZeroIdChecker)
  449. {
  450. var iEquatableDefinition = typeof(IEquatable<>);
  451. var iEquatableType = iEquatableDefinition.MakeGenericType(type);
  452. if (iEquatableType.IsAssignableFrom(type))
  453. {
  454. var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>);
  455. var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type);
  456. idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType);
  457. }
  458. }
  459. else if (__useNullIdChecker)
  460. {
  461. idGenerator = NullIdChecker.Instance;
  462. }
  463. else
  464. {
  465. idGenerator = null;
  466. }
  467. __idGenerators[type] = idGenerator; // remember it even if it's null
  468. }
  469. return idGenerator;
  470. }
  471. finally
  472. {
  473. __configLock.ExitWriteLock();
  474. }
  475. }
  476. /// <summary>
  477. /// Looks up a serializer for a Type.
  478. /// </summary>
  479. /// <param name="type">The Type.</param>
  480. /// <returns>A serializer for the Type.</returns>
  481. public static IBsonSerializer LookupSerializer(Type type)
  482. {
  483. // since we don't allow registering serializers for BsonDocument no lookup is needed
  484. if (type == typeof(BsonDocument))
  485. {
  486. return BsonDocumentSerializer.Instance;
  487. }
  488. __configLock.EnterReadLock();
  489. try
  490. {
  491. IBsonSerializer serializer;
  492. if (__serializers.TryGetValue(type, out serializer))
  493. {
  494. return serializer;
  495. }
  496. }
  497. finally
  498. {
  499. __configLock.ExitReadLock();
  500. }
  501. __configLock.EnterWriteLock();
  502. try
  503. {
  504. IBsonSerializer serializer;
  505. if (!__serializers.TryGetValue(type, out serializer))
  506. {
  507. if (serializer == null)
  508. {
  509. var serializerAttributes = type.GetCustomAttributes(typeof(BsonSerializerAttribute), false); // don't inherit
  510. if (serializerAttributes.Length == 1)
  511. {
  512. var serializerAttribute = (BsonSerializerAttribute)serializerAttributes[0];
  513. serializer = serializerAttribute.CreateSerializer(type);
  514. }
  515. }
  516. if (serializer == null && type.IsGenericType)
  517. {
  518. var genericTypeDefinition = type.GetGenericTypeDefinition();
  519. var genericSerializerDefinition = LookupGenericSerializerDefinition(genericTypeDefinition);
  520. if (genericSerializerDefinition != null)
  521. {
  522. var genericSerializerType = genericSerializerDefinition.MakeGenericType(type.GetGenericArguments());
  523. serializer = (IBsonSerializer)Activator.CreateInstance(genericSerializerType);
  524. }
  525. }
  526. if (serializer == null)
  527. {
  528. foreach (var serializationProvider in __serializationProviders)
  529. {
  530. serializer = serializationProvider.GetSerializer(type);
  531. if (serializer != null)
  532. {
  533. break;
  534. }
  535. }
  536. }
  537. if (serializer == null)
  538. {
  539. var message = string.Format("No serializer found for type {0}.", type.FullName);
  540. throw new BsonSerializationException(message);
  541. }
  542. __serializers[type] = serializer;
  543. }
  544. return serializer;
  545. }
  546. finally
  547. {
  548. __configLock.ExitWriteLock();
  549. }
  550. }
  551. /// <summary>
  552. /// Registers the discriminator for a type.
  553. /// </summary>
  554. /// <param name="type">The type.</param>
  555. /// <param name="discriminator">The discriminator.</param>
  556. public static void RegisterDiscriminator(Type type, BsonValue discriminator)
  557. {
  558. if (type.IsInterface)
  559. {
  560. var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.", type.FullName);
  561. throw new BsonSerializationException(message);
  562. }
  563. __configLock.EnterWriteLock();
  564. try
  565. {
  566. HashSet<Type> hashSet;
  567. if (!__discriminators.TryGetValue(discriminator, out hashSet))
  568. {
  569. hashSet = new HashSet<Type>();
  570. __discriminators.Add(discriminator, hashSet);
  571. }
  572. if (!hashSet.Contains(type))
  573. {
  574. hashSet.Add(type);
  575. // mark all base types as discriminated (so we know that it's worth reading a discriminator)
  576. for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
  577. {
  578. __discriminatedTypes.Add(baseType);
  579. }
  580. }
  581. }
  582. finally
  583. {
  584. __configLock.ExitWriteLock();
  585. }
  586. }
  587. /// <summary>
  588. /// Registers the discriminator convention for a type.
  589. /// </summary>
  590. /// <param name="type">Type type.</param>
  591. /// <param name="convention">The discriminator convention.</param>
  592. public static void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention)
  593. {
  594. __configLock.EnterWriteLock();
  595. try
  596. {
  597. if (!__discriminatorConventions.ContainsKey(type))
  598. {
  599. __discriminatorConventions.Add(type, convention);
  600. }
  601. else
  602. {
  603. var message = string.Format("There is already a discriminator convention registered for type {0}.", type.FullName);
  604. throw new BsonSerializationException(message);
  605. }
  606. }
  607. finally
  608. {
  609. __configLock.ExitWriteLock();
  610. }
  611. }
  612. /// <summary>
  613. /// Registers a generic serializer definition for a generic type.
  614. /// </summary>
  615. /// <param name="genericTypeDefinition">The generic type.</param>
  616. /// <param name="genericSerializerDefinition">The generic serializer definition.</param>
  617. public static void RegisterGenericSerializerDefinition(
  618. Type genericTypeDefinition,
  619. Type genericSerializerDefinition)
  620. {
  621. __configLock.EnterWriteLock();
  622. try
  623. {
  624. __genericSerializerDefinitions[genericTypeDefinition] = genericSerializerDefinition;
  625. }
  626. finally
  627. {
  628. __configLock.ExitWriteLock();
  629. }
  630. }
  631. /// <summary>
  632. /// Registers an IdGenerator for an Id Type.
  633. /// </summary>
  634. /// <param name="type">The Id Type.</param>
  635. /// <param name="idGenerator">The IdGenerator for the Id Type.</param>
  636. public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
  637. {
  638. __configLock.EnterWriteLock();
  639. try
  640. {
  641. __idGenerators[type] = idGenerator;
  642. }
  643. finally
  644. {
  645. __configLock.ExitWriteLock();
  646. }
  647. }
  648. /// <summary>
  649. /// Registers a serialization provider.
  650. /// </summary>
  651. /// <param name="provider">The serialization provider.</param>
  652. public static void RegisterSerializationProvider(IBsonSerializationProvider provider)
  653. {
  654. __configLock.EnterWriteLock();
  655. try
  656. {
  657. // add new provider to the front of the list
  658. __serializationProviders.Insert(0, provider);
  659. }
  660. finally
  661. {
  662. __configLock.ExitWriteLock();
  663. }
  664. }
  665. /// <summary>
  666. /// Registers a serializer for a type.
  667. /// </summary>
  668. /// <param name="type">The type.</param>
  669. /// <param name="serializer">The serializer.</param>
  670. public static void RegisterSerializer(Type type, IBsonSerializer serializer)
  671. {
  672. // don't allow a serializer to be registered for subclasses of BsonValue
  673. if (typeof(BsonValue).IsAssignableFrom(type))
  674. {
  675. var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
  676. throw new BsonSerializationException(message);
  677. }
  678. __configLock.EnterWriteLock();
  679. try
  680. {
  681. if (__serializers.ContainsKey(type))
  682. {
  683. var message = string.Format("There is already a serializer registered for type {0}.", type.FullName);
  684. throw new BsonSerializationException(message);
  685. }
  686. __serializers.Add(type, serializer);
  687. }
  688. finally
  689. {
  690. __configLock.ExitWriteLock();
  691. }
  692. }
  693. /// <summary>
  694. /// Serializes an object to a BsonWriter.
  695. /// </summary>
  696. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  697. /// <param name="bsonWriter">The BsonWriter.</param>
  698. /// <param name="value">The object.</param>
  699. public static void Serialize<TNominalType>(BsonWriter bsonWriter, TNominalType value)
  700. {
  701. Serialize(bsonWriter, value, null);
  702. }
  703. /// <summary>
  704. /// Serializes an object to a BsonWriter.
  705. /// </summary>
  706. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  707. /// <param name="bsonWriter">The BsonWriter.</param>
  708. /// <param name="value">The object.</param>
  709. /// <param name="options">The serialization options.</param>
  710. public static void Serialize<TNominalType>(
  711. BsonWriter bsonWriter,
  712. TNominalType value,
  713. IBsonSerializationOptions options)
  714. {
  715. Serialize(bsonWriter, typeof(TNominalType), value, options);
  716. }
  717. /// <summary>
  718. /// Serializes an object to a BsonWriter.
  719. /// </summary>
  720. /// <param name="bsonWriter">The BsonWriter.</param>
  721. /// <param name="nominalType">The nominal type of the object.</param>
  722. /// <param name="value">The object.</param>
  723. public static void Serialize(BsonWriter bsonWriter, Type nominalType, object value)
  724. {
  725. Serialize(bsonWriter, nominalType, value, null);
  726. }
  727. /// <summary>
  728. /// Serializes an object to a BsonWriter.
  729. /// </summary>
  730. /// <param name="bsonWriter">The BsonWriter.</param>
  731. /// <param name="nominalType">The nominal type of the object.</param>
  732. /// <param name="value">The object.</param>
  733. /// <param name="options">The serialization options.</param>
  734. public static void Serialize(
  735. BsonWriter bsonWriter,
  736. Type nominalType,
  737. object value,
  738. IBsonSerializationOptions options)
  739. {
  740. var actualType = (value == null) ? nominalType : value.GetType();
  741. var serializer = LookupSerializer(actualType);
  742. serializer.Serialize(bsonWriter, nominalType, value, options);
  743. }
  744. // internal static methods
  745. internal static void EnsureKnownTypesAreRegistered(Type nominalType)
  746. {
  747. __configLock.EnterReadLock();
  748. try
  749. {
  750. if (__typesWithRegisteredKnownTypes.Contains(nominalType))
  751. {
  752. return;
  753. }
  754. }
  755. finally
  756. {
  757. __configLock.ExitReadLock();
  758. }
  759. __configLock.EnterWriteLock();
  760. try
  761. {
  762. if (!__typesWithRegisteredKnownTypes.Contains(nominalType))
  763. {
  764. // only call LookupClassMap for classes with a BsonKnownTypesAttribute
  765. var knownTypesAttribute = nominalType.GetCustomAttributes(typeof(BsonKnownTypesAttribute), false);
  766. if (knownTypesAttribute != null && knownTypesAttribute.Length > 0)
  767. {
  768. // try and force a scan of the known types
  769. LookupSerializer(nominalType);
  770. }
  771. __typesWithRegisteredKnownTypes.Add(nominalType);
  772. }
  773. }
  774. finally
  775. {
  776. __configLock.ExitWriteLock();
  777. }
  778. }
  779. // private static methods
  780. private static void RegisterDefaultSerializationProviders()
  781. {
  782. // last one registered gets first chance at providing the serializer
  783. RegisterSerializationProvider(new BsonClassMapSerializationProvider());
  784. RegisterSerializationProvider(new BsonDefaultSerializationProvider());
  785. }
  786. private static void RegisterIdGenerators()
  787. {
  788. RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);
  789. RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance);
  790. RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance);
  791. }
  792. }
  793. }