Skip to content

Commit 1419274

Browse files
author
Robert Stam
committed
Fixed CSHARP-429. List, Queue and Stack and now be serialized/deserialized when the nominal type is object.
1 parent bbe07bb commit 1419274

11 files changed

+570
-206
lines changed

Bson/Bson.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@
219219
<Compile Include="Serialization\Serializers\NetPrimitiveSerializers.cs" />
220220
<Compile Include="Serialization\Serializers\BsonPrimitiveSerializers.cs" />
221221
<Compile Include="Serialization\IBsonSerializationProvider.cs" />
222+
<Compile Include="Serialization\TypeNameDiscriminator.cs" />
222223
</ItemGroup>
223224
<ItemGroup>
224225
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

Bson/Serialization/BsonClassMap.cs

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -239,68 +239,6 @@ public static Type GetMemberInfoType(MemberInfo memberInfo)
239239
throw new NotSupportedException("Only field and properties are supported at this time.");
240240
}
241241

242-
/// <summary>
243-
/// Gets a loadable type name (like AssemblyQualifiedName but shortened when possible)
244-
/// </summary>
245-
/// <param name="type">The type.</param>
246-
/// <returns>The type name.</returns>
247-
public static string GetTypeNameDiscriminator(Type type)
248-
{
249-
if (type == null)
250-
{
251-
throw new ArgumentNullException("type");
252-
}
253-
254-
string typeName;
255-
if (type.IsGenericType)
256-
{
257-
var genericTypeNames = "";
258-
foreach (var genericType in type.GetGenericArguments())
259-
{
260-
var genericTypeName = GetTypeNameDiscriminator(genericType);
261-
if (genericTypeName.IndexOf(',') != -1)
262-
{
263-
genericTypeName = "[" + genericTypeName + "]";
264-
}
265-
if (genericTypeNames != "")
266-
{
267-
genericTypeNames += ",";
268-
}
269-
genericTypeNames += genericTypeName;
270-
}
271-
typeName = type.GetGenericTypeDefinition().FullName + "[" + genericTypeNames + "]";
272-
}
273-
else
274-
{
275-
typeName = type.FullName;
276-
}
277-
278-
string assemblyName = type.Assembly.FullName;
279-
Match match = Regex.Match(assemblyName, "(?<dll>[^,]+), Version=[^,]+, Culture=[^,]+, PublicKeyToken=(?<token>[^,]+)");
280-
if (match.Success)
281-
{
282-
var dll = match.Groups["dll"].Value;
283-
var publicKeyToken = match.Groups["token"].Value;
284-
if (dll == "mscorlib")
285-
{
286-
assemblyName = null;
287-
}
288-
else if (publicKeyToken == "null")
289-
{
290-
assemblyName = dll;
291-
}
292-
}
293-
294-
if (assemblyName == null)
295-
{
296-
return typeName;
297-
}
298-
else
299-
{
300-
return typeName + ", " + assemblyName;
301-
}
302-
}
303-
304242
/// <summary>
305243
/// Checks whether a class map is registered for a type.
306244
/// </summary>

Bson/Serialization/BsonDefaultSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public static Type LookupActualType(Type nominalType, BsonValue discriminator)
210210

211211
if (actualType == null && discriminator.IsString)
212212
{
213-
actualType = Type.GetType(discriminator.AsString); // see if it's a Type name
213+
actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name
214214
}
215215

216216
if (actualType == null)

Bson/Serialization/Serializers/ArraySerializer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public override void Serialize(
125125
if (nominalType == typeof(object))
126126
{
127127
bsonWriter.WriteStartDocument();
128-
bsonWriter.WriteString("_t", BsonClassMap.GetTypeNameDiscriminator(actualType));
128+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
129129
bsonWriter.WriteName("_v");
130130
Serialize(bsonWriter, actualType, value, options);
131131
bsonWriter.WriteEndDocument();
@@ -258,7 +258,7 @@ public override void Serialize(
258258
if (nominalType == typeof(object))
259259
{
260260
bsonWriter.WriteStartDocument();
261-
bsonWriter.WriteString("_t", BsonClassMap.GetTypeNameDiscriminator(actualType));
261+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
262262
bsonWriter.WriteName("_v");
263263
Serialize(bsonWriter, actualType, value, options);
264264
bsonWriter.WriteEndDocument();
@@ -415,7 +415,7 @@ public override void Serialize(
415415
if (nominalType == typeof(object))
416416
{
417417
bsonWriter.WriteStartDocument();
418-
bsonWriter.WriteString("_t", BsonClassMap.GetTypeNameDiscriminator(actualType));
418+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
419419
bsonWriter.WriteName("_v");
420420
Serialize(bsonWriter, actualType, value, options);
421421
bsonWriter.WriteEndDocument();

Bson/Serialization/Serializers/CollectionGenericSerializers.cs

Lines changed: 114 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,34 @@ public override object Deserialize(
5757
IBsonSerializationOptions options)
5858
{
5959
var bsonType = bsonReader.GetCurrentBsonType();
60-
if (bsonType == BsonType.Null)
60+
switch (bsonType)
6161
{
62-
bsonReader.ReadNull();
63-
return null;
64-
}
65-
else if (bsonType == BsonType.Array)
66-
{
67-
bsonReader.ReadStartArray();
68-
var list = (nominalType == typeof(List<T>) || nominalType.IsInterface) ? new List<T>() : (ICollection<T>)Activator.CreateInstance(nominalType);
69-
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
70-
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
71-
{
72-
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
73-
var serializer = BsonSerializer.LookupSerializer(elementType);
74-
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
75-
list.Add(element);
76-
}
77-
bsonReader.ReadEndArray();
78-
return list;
79-
}
80-
else
81-
{
82-
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
83-
throw new FileFormatException(message);
62+
case BsonType.Null:
63+
bsonReader.ReadNull();
64+
return null;
65+
case BsonType.Array:
66+
bsonReader.ReadStartArray();
67+
var list = (nominalType == typeof(List<T>) || nominalType.IsInterface) ? new List<T>() : (ICollection<T>)Activator.CreateInstance(nominalType);
68+
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
69+
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
70+
{
71+
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
72+
var serializer = BsonSerializer.LookupSerializer(elementType);
73+
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
74+
list.Add(element);
75+
}
76+
bsonReader.ReadEndArray();
77+
return list;
78+
case BsonType.Document:
79+
bsonReader.ReadStartDocument();
80+
bsonReader.ReadString("_t"); // skip over discriminator
81+
bsonReader.ReadName("_v");
82+
var value = Deserialize(bsonReader, actualType, actualType, options);
83+
bsonReader.ReadEndDocument();
84+
return value;
85+
default:
86+
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
87+
throw new FileFormatException(message);
8488
}
8589
}
8690

@@ -116,6 +120,17 @@ public override void Serialize(
116120
}
117121
else
118122
{
123+
if (nominalType == typeof(object))
124+
{
125+
var actualType = value.GetType();
126+
bsonWriter.WriteStartDocument();
127+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
128+
bsonWriter.WriteName("_v");
129+
Serialize(bsonWriter, actualType, value, options);
130+
bsonWriter.WriteEndDocument();
131+
return;
132+
}
133+
119134
var items = (IEnumerable<T>)value;
120135
var arraySerializationOptions = EnsureSerializationOptions<ArraySerializationOptions>(options);
121136
var itemSerializationOptions = arraySerializationOptions.ItemSerializationOptions;
@@ -161,30 +176,34 @@ public override object Deserialize(
161176
IBsonSerializationOptions options)
162177
{
163178
var bsonType = bsonReader.GetCurrentBsonType();
164-
if (bsonType == BsonType.Null)
165-
{
166-
bsonReader.ReadNull();
167-
return null;
168-
}
169-
else if (bsonType == BsonType.Array)
170-
{
171-
bsonReader.ReadStartArray();
172-
var queue = new Queue<T>();
173-
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
174-
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
175-
{
176-
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
177-
var serializer = BsonSerializer.LookupSerializer(elementType);
178-
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
179-
queue.Enqueue(element);
180-
}
181-
bsonReader.ReadEndArray();
182-
return queue;
183-
}
184-
else
179+
switch (bsonType)
185180
{
186-
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
187-
throw new FileFormatException(message);
181+
case BsonType.Null:
182+
bsonReader.ReadNull();
183+
return null;
184+
case BsonType.Array:
185+
bsonReader.ReadStartArray();
186+
var queue = new Queue<T>();
187+
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
188+
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
189+
{
190+
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
191+
var serializer = BsonSerializer.LookupSerializer(elementType);
192+
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
193+
queue.Enqueue(element);
194+
}
195+
bsonReader.ReadEndArray();
196+
return queue;
197+
case BsonType.Document:
198+
bsonReader.ReadStartDocument();
199+
bsonReader.ReadString("_t"); // skip over discriminator
200+
bsonReader.ReadName("_v");
201+
var value = Deserialize(bsonReader, actualType, actualType, options);
202+
bsonReader.ReadEndDocument();
203+
return value;
204+
default:
205+
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
206+
throw new FileFormatException(message);
188207
}
189208
}
190209

@@ -220,6 +239,17 @@ public override void Serialize(
220239
}
221240
else
222241
{
242+
if (nominalType == typeof(object))
243+
{
244+
var actualType = value.GetType();
245+
bsonWriter.WriteStartDocument();
246+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
247+
bsonWriter.WriteName("_v");
248+
Serialize(bsonWriter, actualType, value, options);
249+
bsonWriter.WriteEndDocument();
250+
return;
251+
}
252+
223253
var items = (Queue<T>)value;
224254
var arraySerializationOptions = EnsureSerializationOptions<ArraySerializationOptions>(options);
225255
var itemSerializationOptions = arraySerializationOptions.ItemSerializationOptions;
@@ -265,30 +295,34 @@ public override object Deserialize(
265295
IBsonSerializationOptions options)
266296
{
267297
var bsonType = bsonReader.GetCurrentBsonType();
268-
if (bsonType == BsonType.Null)
298+
switch (bsonType)
269299
{
270-
bsonReader.ReadNull();
271-
return null;
272-
}
273-
else if (bsonType == BsonType.Array)
274-
{
275-
bsonReader.ReadStartArray();
276-
var stack = new Stack<T>();
277-
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
278-
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
279-
{
280-
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
281-
var serializer = BsonSerializer.LookupSerializer(elementType);
282-
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
283-
stack.Push(element);
284-
}
285-
bsonReader.ReadEndArray();
286-
return stack;
287-
}
288-
else
289-
{
290-
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
291-
throw new FileFormatException(message);
300+
case BsonType.Null:
301+
bsonReader.ReadNull();
302+
return null;
303+
case BsonType.Array:
304+
bsonReader.ReadStartArray();
305+
var stack = new Stack<T>();
306+
var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(T));
307+
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
308+
{
309+
var elementType = discriminatorConvention.GetActualType(bsonReader, typeof(T));
310+
var serializer = BsonSerializer.LookupSerializer(elementType);
311+
var element = (T)serializer.Deserialize(bsonReader, typeof(T), elementType, null);
312+
stack.Push(element);
313+
}
314+
bsonReader.ReadEndArray();
315+
return stack;
316+
case BsonType.Document:
317+
bsonReader.ReadStartDocument();
318+
bsonReader.ReadString("_t"); // skip over discriminator
319+
bsonReader.ReadName("_v");
320+
var value = Deserialize(bsonReader, actualType, actualType, options);
321+
bsonReader.ReadEndDocument();
322+
return value;
323+
default:
324+
var message = string.Format("Can't deserialize a {0} from BsonType {1}.", nominalType.FullName, bsonType);
325+
throw new FileFormatException(message);
292326
}
293327
}
294328

@@ -324,6 +358,17 @@ public override void Serialize(
324358
}
325359
else
326360
{
361+
if (nominalType == typeof(object))
362+
{
363+
var actualType = value.GetType();
364+
bsonWriter.WriteStartDocument();
365+
bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType));
366+
bsonWriter.WriteName("_v");
367+
Serialize(bsonWriter, actualType, value, options);
368+
bsonWriter.WriteEndDocument();
369+
return;
370+
}
371+
327372
var items = ((Stack<T>)value).ToArray(); // convert to array to allow efficient access in reverse order
328373
var arraySerializationOptions = EnsureSerializationOptions<ArraySerializationOptions>(options);
329374
var itemSerializationOptions = arraySerializationOptions.ItemSerializationOptions;

0 commit comments

Comments
 (0)