Skip to content

Commit

Permalink
CSHARP-4475: Add an AllowedTypes filter to ObjectSerializer.
Browse files Browse the repository at this point in the history
  • Loading branch information
rstam committed Jan 26, 2023
1 parent 8993daa commit 790f123
Show file tree
Hide file tree
Showing 32 changed files with 845 additions and 49 deletions.
22 changes: 22 additions & 0 deletions src/MongoDB.Bson/Serialization/BsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,28 @@ public static void RegisterSerializer(Type type, IBsonSerializer serializer)
serializer.Serialize(context, args, value);
}

/// <summary>
/// Tries to register a serializer for a type.
/// </summary>
/// <param name="serializer">The serializer.</param>
/// <param name="type">The type.</param>
/// <returns>True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.</returns>
public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
{
return __serializerRegistry.TryRegisterSerializer(type, serializer);
}

/// <summary>
/// Tries to register a serializer for a type.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="serializer">The serializer.</param>
/// <returns>True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.</returns>
public static bool TryRegisterSerializer<T>(IBsonSerializer<T> serializer)
{
return TryRegisterSerializer(typeof(T), serializer);
}

// internal static methods
internal static void EnsureKnownTypesAreRegistered(Type nominalType)
{
Expand Down
61 changes: 50 additions & 11 deletions src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,7 @@ public void RegisterSerializer(Type type, IBsonSerializer serializer)
{
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");
}
EnsureRegisteringASerializerForThisTypeIsAllowed(type);

if (!_cache.TryAdd(type, serializer))
{
Expand All @@ -127,6 +117,40 @@ public void RegisterSerializationProvider(IBsonSerializationProvider serializati
_serializationProviders.Push(serializationProvider);
}

/// <summary>
/// Tries to register the serializer.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="serializer">The serializer.</param>
/// <returns>True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.</returns>
public bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (serializer == null)
{
throw new ArgumentNullException(nameof(serializer));
}
EnsureRegisteringASerializerForThisTypeIsAllowed(type);

if (_cache.TryAdd(type, serializer))
{
return true;
}
else
{
var existingSerializer = _cache[type];
if (!existingSerializer.Equals(serializer))
{
var message = $"There is already a different serializer registered for type {BsonUtils.GetFriendlyTypeName(type)}.";
throw new BsonSerializationException(message);
}
return false;
}
}

// private methods
private IBsonSerializer CreateSerializer(Type type)
{
Expand All @@ -153,5 +177,20 @@ private IBsonSerializer CreateSerializer(Type type)
var message = string.Format("No serializer found for type {0}.", type.FullName);
throw new BsonSerializationException(message);
}

private void EnsureRegisteringASerializerForThisTypeIsAllowed(Type type)
{
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");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -651,13 +651,23 @@ private void SerializeDiscriminator(BsonSerializationContext context, Type nomin

private void SerializeMember(BsonSerializationContext context, object obj, BsonMemberMap memberMap)
{
if (memberMap != _classMap.ExtraElementsMemberMap)
try
{
SerializeNormalMember(context, obj, memberMap);
if (memberMap != _classMap.ExtraElementsMemberMap)
{
SerializeNormalMember(context, obj, memberMap);
}
else
{
SerializeExtraElements(context, obj, memberMap);
}
}
else
catch (Exception ex)
{
SerializeExtraElements(context, obj, memberMap);
var message = string.Format(
"An error occurred while serializing the {0} {1} of class {2}: {3}", // terminating period provided by nested message
memberMap.MemberName, (memberMap.MemberInfo is FieldInfo) ? "field" : "property", memberMap.ClassMap.ClassType.FullName, ex.Message);
throw new BsonSerializationException(message, ex);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Options;

Expand Down Expand Up @@ -59,7 +58,7 @@ public DictionarySerializerBase()
/// </summary>
/// <param name="dictionaryRepresentation">The dictionary representation.</param>
public DictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation)
: this(dictionaryRepresentation, new ObjectSerializer(), new ObjectSerializer())
: this(dictionaryRepresentation, BsonSerializer.LookupSerializer<object>(), BsonSerializer.LookupSerializer<object>())
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo

_interfaceType = typeof(TInterface);
_discriminatorConvention = discriminatorConvention;
_objectSerializer = new ObjectSerializer(_discriminatorConvention);
_objectSerializer = ((ObjectSerializer)BsonSerializer.LookupSerializer<object>()).WithDiscriminatorConvention(_discriminatorConvention);
_interfaceSerializer = interfaceSerializer;
}

Expand Down
Loading

0 comments on commit 790f123

Please sign in to comment.