Browse Source

The changes for ShouldSerializeXXX implementation

pull/56/head
saleemjavid 14 years ago
parent
commit
950b293fcd
  1. 14
      Bson/Serialization/BsonClassMap.cs
  2. 4
      Bson/Serialization/BsonClassMapSerializer.cs
  3. 45
      Bson/Serialization/BsonMemberMap.cs
  4. 36
      BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs

14
Bson/Serialization/BsonClassMap.cs

@ -34,6 +34,7 @@ namespace MongoDB.Bson.Serialization {
/// </summary>
public abstract class BsonClassMap {
#region private static fields
private static object staticLock = new object();
private static List<FilteredConventionProfile> profiles = new List<FilteredConventionProfile>();
private static ConventionProfile defaultProfile = ConventionProfile.GetDefault();
private static Dictionary<Type, BsonClassMap> classMaps = new Dictionary<Type, BsonClassMap>();
@ -235,7 +236,7 @@ namespace MongoDB.Bson.Serialization {
public static BsonClassMap LookupClassMap(
Type classType
) {
lock (BsonSerializer.ConfigLock) {
lock (staticLock) {
BsonClassMap classMap;
if (!classMaps.TryGetValue(classType, out classMap)) {
// automatically create a classMap for classType and register it
@ -296,7 +297,7 @@ namespace MongoDB.Bson.Serialization {
public static void RegisterClassMap(
BsonClassMap classMap
) {
lock (BsonSerializer.ConfigLock) {
lock (staticLock) {
// note: class maps can NOT be replaced (because derived classes refer to existing instance)
classMaps.Add(classMap.ClassType, classMap);
BsonDefaultSerializer.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
@ -346,7 +347,7 @@ namespace MongoDB.Bson.Serialization {
/// </summary>
/// <returns>The class map.</returns>
public BsonClassMap Freeze() {
lock (BsonSerializer.ConfigLock) {
lock (staticLock) {
if (!frozen) {
freezeNestingLevel++;
try {
@ -806,7 +807,12 @@ namespace MongoDB.Bson.Serialization {
var defaultValue = conventions.DefaultValueConvention.GetDefaultValue(memberInfo);
if (defaultValue != null) {
memberMap.SetDefaultValue(defaultValue);
}
}
// see if there is a function called ShouldSerializeXXX in the type definition with the signature
// public bool ShouldSerializeXXX();
// if it exists then it will be checked before the member is serialized.
memberMap.SetShouldSerializeValueMethod(memberInfo);
foreach (var attribute in memberInfo.GetCustomAttributes(false)) {
var defaultValueAttribute = attribute as BsonDefaultValueAttribute;

4
Bson/Serialization/BsonClassMapSerializer.cs

@ -320,6 +320,10 @@ namespace MongoDB.Bson.Serialization {
if (memberMap.HasDefaultValue && !memberMap.SerializeDefaultValue && object.Equals(value, memberMap.DefaultValue)) {
return; // don't serialize default value
}
if (!memberMap.ShouldSerializeValue(obj))
{
return;// the object determined that it does not need serialization.
}
bsonWriter.WriteName(memberMap.ElementName);
var nominalType = memberMap.MemberType;

45
Bson/Serialization/BsonMemberMap.cs

@ -45,7 +45,8 @@ namespace MongoDB.Bson.Serialization {
private IIdGenerator idGenerator;
private bool isRequired;
private bool hasDefaultValue;
private bool serializeDefaultValue = true;
private bool serializeDefaultValue = true;
private Func<object, bool> shouldSerializeValueMethod = (instance) => true;
private bool ignoreIfNull;
private object defaultValue;
#endregion
@ -180,6 +181,11 @@ namespace MongoDB.Bson.Serialization {
/// </summary>
public bool SerializeDefaultValue {
get { return serializeDefaultValue; }
}
public Func<object, bool> ShouldSerializeValue
{
get { return shouldSerializeValueMethod; }
}
/// <summary>
@ -359,10 +365,45 @@ namespace MongoDB.Bson.Serialization {
) {
this.serializeDefaultValue = serializeDefaultValue;
return this;
}
/// <summary>
/// Sets the ShouldSerializeValue handler which will determine if the value should be
/// serialized
/// </summary>
/// <param name="methodInfo">The MemberInfo that needs to be checked for ShouldSerializeXXX method </param>
/// <returns>The member map.</returns>
public BsonMemberMap SetShouldSerializeValueMethod(MemberInfo memberInfo)
{
// see if there is a function called ShouldSerializeXXX in the type definition with the signature
// public bool ShouldSerializeXXX();
// if it exists then it will be checked before the member is serialized.
MethodInfo shouldSerializeMethod = null;
var memberName = memberInfo.Name;
var declaringType = memberInfo.DeclaringType;
// Search for a method which has the name ShouldSerializeXXX and takes no arguments
shouldSerializeMethod = declaringType.GetMethod("ShouldSerialize" + memberName, new Type[] { });
if (shouldSerializeMethod != null &&
shouldSerializeMethod.IsPublic &&
shouldSerializeMethod.ReturnType == typeof(bool))
{
var instance = Expression.Parameter(typeof(object), "obj");
var mce = Expression.Call(
Expression.Convert(instance, declaringType),
shouldSerializeMethod);
var lambda = Expression.Lambda<Func<object, bool>>(mce, instance);
shouldSerializeValueMethod = lambda.Compile();
}
return this;
}
#endregion
#region private methods
#region private methods
private Action<object, object> GetFieldSetter() {
var fieldInfo = (FieldInfo) memberInfo;

36
BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs

@ -215,4 +215,40 @@ namespace MongoDB.BsonUnitTests.Serialization {
Assert.AreEqual("X", memberMap.MemberName);
}
}
[TestFixture]
public class BsonShouldSerializeTests {
public class ClassA
{
public string LocalName { get; set; }
public DateTime AsOfUtc { get; set; }
public bool ShouldSerializeAsOfUtc()
{
return this.AsOfUtc != DateTime.MinValue;
}
}
[Test]
public void TestShouldSerializeSuccess() {
var c = new ClassA();
c.AsOfUtc = DateTime.MinValue;
c.LocalName = "Saleem";
var json = c.ToJson();
var expected = "{ 'LocalName' : 'Saleem' }".Replace("'", "\"");
Assert.AreEqual(expected, json);
// Test to see if the value is serialized
var date = new DateTime(2011, 4, 24, 0, 0, 0);
date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
c.AsOfUtc = date;
expected = "{ 'LocalName' : 'Saleem', 'AsOfUtc' : ISODate('2011-04-24T00:00:00Z') }".Replace("'", "\"");
json = c.ToJson();
Assert.AreEqual(expected, json);
}
}
}
Loading…
Cancel
Save