Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,49 +50,65 @@ public EnumRepresentationConvention(BsonType representation)
/// <param name="memberMap">The member map.</param>
public void Apply(BsonMemberMap memberMap)
{
var memberType = memberMap.MemberType;
var memberTypeInfo = memberType.GetTypeInfo();
var serializer = memberMap.GetSerializer();
var reconfiguredSerializer = Apply(serializer);
if (reconfiguredSerializer != null)
{
memberMap.SetSerializer(reconfiguredSerializer);
}
}

private IBsonSerializer Apply(IBsonSerializer serializer)
{
#if NETSTANDARD1_5 || NETSTANDARD1_6
var type = serializer.ValueType.GetTypeInfo();
#else
var type = serializer.ValueType;
#endif

if (memberTypeInfo.IsEnum)
if (type.IsEnum)
{
var serializer = memberMap.GetSerializer();
var representationConfigurableSerializer = serializer as IRepresentationConfigurable;
if (representationConfigurableSerializer != null)
{
var reconfiguredSerializer = representationConfigurableSerializer.WithRepresentation(_representation);
memberMap.SetSerializer(reconfiguredSerializer);
return reconfiguredSerializer;
}
return;
}

if (IsNullableEnum(memberType))
// order matters
var childSerializersConfigurableSerializer = serializer as IChildSerializersConfigurable;
if (childSerializersConfigurableSerializer != null)
{
var childSerializers = childSerializersConfigurableSerializer.ChildSerializers;
for (int i = 0; i < childSerializers.Count; i++)
{
var reconfiguredChildSerializer = Apply(childSerializers[i]);
if (reconfiguredChildSerializer != null)
{
var reconfiguredSerializer = childSerializersConfigurableSerializer.WithChildSerializer(i, reconfiguredChildSerializer);
return reconfiguredSerializer;
}
}
}
else
{
var serializer = memberMap.GetSerializer();
var childSerializerConfigurableSerializer = serializer as IChildSerializerConfigurable;
if (childSerializerConfigurableSerializer != null)
{
var childSerializer = childSerializerConfigurableSerializer.ChildSerializer;
var representationConfigurableChildSerializer = childSerializer as IRepresentationConfigurable;
if (representationConfigurableChildSerializer != null)
var reconfiguredChildSerializer = Apply(childSerializer);
if (reconfiguredChildSerializer != null)
{
var reconfiguredChildSerializer = representationConfigurableChildSerializer.WithRepresentation(_representation);
var reconfiguredSerializer = childSerializerConfigurableSerializer.WithChildSerializer(reconfiguredChildSerializer);
memberMap.SetSerializer(reconfiguredSerializer);
return reconfiguredSerializer;
}
}
return;
}
}

// private methods
private bool IsNullableEnum(Type type)
{
return
type.GetTypeInfo().IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
Nullable.GetUnderlyingType(type).GetTypeInfo().IsEnum;
return null;
}

// private methods
private void EnsureRepresentationIsValidForEnums(BsonType representation)
{
if (
Expand Down
46 changes: 46 additions & 0 deletions src/MongoDB.Bson/Serialization/IChildSerializersConfigurable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Copyright 2010-2014 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.Collections.Generic;

namespace MongoDB.Bson.Serialization
{
// this interface is public so custom serializers with several child serializers can choose to implement it
// but typically you would choose to implement this interface explicitly
// these methods support forwarding attributes to child serializers and wouldn't normally be public

/// <summary>
/// Represents a serializer that has multiple child serializers that configuration attributes can be forwarded to.
/// Each child serializer gets identified by an index.
/// </summary>
public interface IChildSerializersConfigurable
{
/// <summary>
/// Gets the child serializer.
/// </summary>
/// <value>
/// The child serializer.
/// </value>
IList<IBsonSerializer> ChildSerializers { get; }

/// <summary>
/// Returns a serializer that has been reconfigured with the specified child serializer.
/// </summary>
/// <param name="serializerIndex">The index of the child serializer.</param>
/// <param name="childSerializer">The child serializer.</param>
/// <returns>The reconfigured serializer.</returns>
IBsonSerializer WithChildSerializer(int serializerIndex, IBsonSerializer childSerializer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace MongoDB.Bson.Serialization.Serializers
public class DictionaryInterfaceImplementerSerializer<TDictionary> :
DictionarySerializerBase<TDictionary>,
IChildSerializerConfigurable,
IChildSerializersConfigurable,
IDictionaryRepresentationConfigurable
where TDictionary : class, IDictionary, new()
{
Expand Down Expand Up @@ -154,6 +155,31 @@ IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentati
{
return WithDictionaryRepresentation(dictionaryRepresentation);
}

IList<IBsonSerializer> IChildSerializersConfigurable.ChildSerializers
{
get
{
return new[]
{
KeySerializer,
ValueSerializer,
};
}
}

IBsonSerializer IChildSerializersConfigurable.WithChildSerializer(int serializerIndex, IBsonSerializer childSerializer)
{
switch (serializerIndex)
{
case 0:
return WithKeySerializer(childSerializer);
case 1:
return WithValueSerializer(childSerializer);
}

return null;
}
}

/// <summary>
Expand All @@ -165,6 +191,7 @@ IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentati
public class DictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> :
DictionarySerializerBase<TDictionary, TKey, TValue>,
IChildSerializerConfigurable,
IChildSerializersConfigurable,
IDictionaryRepresentationConfigurable<DictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>>
where TDictionary : class, IDictionary<TKey, TValue>
{
Expand Down Expand Up @@ -281,6 +308,31 @@ IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentati
{
return WithDictionaryRepresentation(dictionaryRepresentation);
}

IList<IBsonSerializer> IChildSerializersConfigurable.ChildSerializers
{
get
{
return new IBsonSerializer[]
{
KeySerializer,
ValueSerializer,
};
}
}

IBsonSerializer IChildSerializersConfigurable.WithChildSerializer(int serializerIndex, IBsonSerializer childSerializer)
{
switch (serializerIndex)
{
case 0:
return WithKeySerializer((IBsonSerializer<TKey>) childSerializer);
case 1:
return WithValueSerializer((IBsonSerializer<TValue>) childSerializer);
}

return null;
}

/// <inheritdoc/>
protected override ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using FluentAssertions;
using MongoDB.Bson.Serialization;
Expand All @@ -32,6 +33,10 @@ public class C
public E E { get; set; }
public E? NE { get; set; }
public int I { get; set; }
public List<E> L { get; set; }
public List<List<List<E>>> L3 { get; set; }
public Dictionary<E, int> DK { get; set; }
public Dictionary<int, E> DV { get; set; }
}

[Theory]
Expand All @@ -48,7 +53,6 @@ public void Apply_should_configure_serializer_when_member_is_an_enum(BsonType re
serializer.Representation.Should().Be(representation);
}


[Theory]
[InlineData(BsonType.Int32)]
[InlineData(BsonType.Int64)]
Expand All @@ -64,6 +68,64 @@ public void Apply_should_configure_serializer_when_member_is_a_nullable_enum(Bso
childSerializer.Representation.Should().Be(representation);
}

[Theory]
[InlineData(BsonType.Int32)]
[InlineData(BsonType.Int64)]
public void Apply_should_configure_serializer_when_member_is_a_dictionary_with_enum_keys(BsonType representation)
{
var subject = new EnumRepresentationConvention(representation);
var memberMap = CreateMemberMap(c => c.DK);

subject.Apply(memberMap);

var serializer = (DictionaryInterfaceImplementerSerializer<Dictionary<E, int>, E, int>)memberMap.GetSerializer();
((IRepresentationConfigurable)serializer.KeySerializer).Representation.Should().Be(representation);
}

[Theory]
[InlineData(BsonType.Int32)]
[InlineData(BsonType.Int64)]
public void Apply_should_configure_serializer_when_member_is_a_dictionary_with_enum_values(BsonType representation)
{
var subject = new EnumRepresentationConvention(representation);
var memberMap = CreateMemberMap(c => c.DV);

subject.Apply(memberMap);

var serializer = (DictionaryInterfaceImplementerSerializer<Dictionary<int, E>, int, E>)memberMap.GetSerializer();
((IRepresentationConfigurable)serializer.ValueSerializer).Representation.Should().Be(representation);
}

[Theory]
[InlineData(BsonType.Int32)]
[InlineData(BsonType.Int64)]
public void Apply_should_configure_serializer_when_member_is_a_collection_of_enums(BsonType representation)
{
var subject = new EnumRepresentationConvention(representation);
var memberMap = CreateMemberMap(c => c.L);

subject.Apply(memberMap);

var serializer = (EnumerableInterfaceImplementerSerializer<List<E>, E>)memberMap.GetSerializer();
((IRepresentationConfigurable)serializer.ItemSerializer).Representation.Should().Be(representation);
}

[Theory]
[InlineData(BsonType.Int32)]
[InlineData(BsonType.Int64)]
public void Apply_should_configure_serializer_when_member_is_a_nested_collection_of_enums(BsonType representation)
{
var subject = new EnumRepresentationConvention(representation);
var memberMap = CreateMemberMap(c => c.L3);

subject.Apply(memberMap);

var serializer = (IChildSerializerConfigurable)memberMap.GetSerializer();
serializer = (IChildSerializerConfigurable)serializer.ChildSerializer;
var childSerializer = (EnumerableInterfaceImplementerSerializer<List<E>, E>)serializer.ChildSerializer;
((IRepresentationConfigurable)childSerializer.ItemSerializer).Representation.Should().Be(representation);
}

[Fact]
public void Apply_should_do_nothing_when_member_is_not_an_enum()
{
Expand Down