Skip to content

Commit 790f123

Browse files
committed
CSHARP-4475: Add an AllowedTypes filter to ObjectSerializer.
1 parent 8993daa commit 790f123

32 files changed

+845
-49
lines changed

src/MongoDB.Bson/Serialization/BsonSerializer.cs

+22
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,28 @@ public static void Serialize(
678678
serializer.Serialize(context, args, value);
679679
}
680680

681+
/// <summary>
682+
/// Tries to register a serializer for a type.
683+
/// </summary>
684+
/// <param name="serializer">The serializer.</param>
685+
/// <param name="type">The type.</param>
686+
/// <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>
687+
public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
688+
{
689+
return __serializerRegistry.TryRegisterSerializer(type, serializer);
690+
}
691+
692+
/// <summary>
693+
/// Tries to register a serializer for a type.
694+
/// </summary>
695+
/// <typeparam name="T">The type.</typeparam>
696+
/// <param name="serializer">The serializer.</param>
697+
/// <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>
698+
public static bool TryRegisterSerializer<T>(IBsonSerializer<T> serializer)
699+
{
700+
return TryRegisterSerializer(typeof(T), serializer);
701+
}
702+
681703
// internal static methods
682704
internal static void EnsureKnownTypesAreRegistered(Type nominalType)
683705
{

src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs

+50-11
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,7 @@ public void RegisterSerializer(Type type, IBsonSerializer serializer)
9393
{
9494
throw new ArgumentNullException("serializer");
9595
}
96-
var typeInfo = type.GetTypeInfo();
97-
if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type))
98-
{
99-
var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
100-
throw new BsonSerializationException(message);
101-
}
102-
if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
103-
{
104-
var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
105-
throw new ArgumentException(message, "type");
106-
}
96+
EnsureRegisteringASerializerForThisTypeIsAllowed(type);
10797

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

120+
/// <summary>
121+
/// Tries to register the serializer.
122+
/// </summary>
123+
/// <param name="type">The type.</param>
124+
/// <param name="serializer">The serializer.</param>
125+
/// <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>
126+
public bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
127+
{
128+
if (type == null)
129+
{
130+
throw new ArgumentNullException(nameof(type));
131+
}
132+
if (serializer == null)
133+
{
134+
throw new ArgumentNullException(nameof(serializer));
135+
}
136+
EnsureRegisteringASerializerForThisTypeIsAllowed(type);
137+
138+
if (_cache.TryAdd(type, serializer))
139+
{
140+
return true;
141+
}
142+
else
143+
{
144+
var existingSerializer = _cache[type];
145+
if (!existingSerializer.Equals(serializer))
146+
{
147+
var message = $"There is already a different serializer registered for type {BsonUtils.GetFriendlyTypeName(type)}.";
148+
throw new BsonSerializationException(message);
149+
}
150+
return false;
151+
}
152+
}
153+
130154
// private methods
131155
private IBsonSerializer CreateSerializer(Type type)
132156
{
@@ -153,5 +177,20 @@ private IBsonSerializer CreateSerializer(Type type)
153177
var message = string.Format("No serializer found for type {0}.", type.FullName);
154178
throw new BsonSerializationException(message);
155179
}
180+
181+
private void EnsureRegisteringASerializerForThisTypeIsAllowed(Type type)
182+
{
183+
var typeInfo = type.GetTypeInfo();
184+
if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type))
185+
{
186+
var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
187+
throw new BsonSerializationException(message);
188+
}
189+
if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
190+
{
191+
var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
192+
throw new ArgumentException(message, "type");
193+
}
194+
}
156195
}
157196
}

src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs

+14-4
Original file line numberDiff line numberDiff line change
@@ -651,13 +651,23 @@ private void SerializeDiscriminator(BsonSerializationContext context, Type nomin
651651

652652
private void SerializeMember(BsonSerializationContext context, object obj, BsonMemberMap memberMap)
653653
{
654-
if (memberMap != _classMap.ExtraElementsMemberMap)
654+
try
655655
{
656-
SerializeNormalMember(context, obj, memberMap);
656+
if (memberMap != _classMap.ExtraElementsMemberMap)
657+
{
658+
SerializeNormalMember(context, obj, memberMap);
659+
}
660+
else
661+
{
662+
SerializeExtraElements(context, obj, memberMap);
663+
}
657664
}
658-
else
665+
catch (Exception ex)
659666
{
660-
SerializeExtraElements(context, obj, memberMap);
667+
var message = string.Format(
668+
"An error occurred while serializing the {0} {1} of class {2}: {3}", // terminating period provided by nested message
669+
memberMap.MemberName, (memberMap.MemberInfo is FieldInfo) ? "field" : "property", memberMap.ClassMap.ClassType.FullName, ex.Message);
670+
throw new BsonSerializationException(message, ex);
661671
}
662672
}
663673

src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
using System;
1717
using System.Collections;
1818
using System.Collections.Generic;
19-
using System.Linq.Expressions;
2019
using MongoDB.Bson.IO;
2120
using MongoDB.Bson.Serialization.Options;
2221

@@ -59,7 +58,7 @@ public DictionarySerializerBase()
5958
/// </summary>
6059
/// <param name="dictionaryRepresentation">The dictionary representation.</param>
6160
public DictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation)
62-
: this(dictionaryRepresentation, new ObjectSerializer(), new ObjectSerializer())
61+
: this(dictionaryRepresentation, BsonSerializer.LookupSerializer<object>(), BsonSerializer.LookupSerializer<object>())
6362
{
6463
}
6564

src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo
8181

8282
_interfaceType = typeof(TInterface);
8383
_discriminatorConvention = discriminatorConvention;
84-
_objectSerializer = new ObjectSerializer(_discriminatorConvention);
84+
_objectSerializer = ((ObjectSerializer)BsonSerializer.LookupSerializer<object>()).WithDiscriminatorConvention(_discriminatorConvention);
8585
_interfaceSerializer = interfaceSerializer;
8686
}
8787

0 commit comments

Comments
 (0)