Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added default constructor to BsonElementAttribute. removed constraint…

…s related to mapping readonly fields and properties. added support for persisting readonly fields and properties and not deserializing them.
  • Loading branch information...
commit 24813c21ad9f1ae328b4f9aae9f08ce0c91a582e 1 parent 8bf97a8
@craiggwilson craiggwilson authored
View
3  .gitignore
@@ -27,3 +27,6 @@ Help
#Nupkg artifacts
*.nupkg
+
+# NCrunch artifacts
+*.ncrunch*
View
6 Bson/Serialization/Attributes/BsonElementAttribute.cs
@@ -34,6 +34,12 @@ public class BsonElementAttribute : BsonSerializationOptionsAttribute
/// <summary>
/// Initializes a new instance of the BsonElementAttribute class.
/// </summary>
+ public BsonElementAttribute()
+ { }
+
+ /// <summary>
+ /// Initializes a new instance of the BsonElementAttribute class.
+ /// </summary>
/// <param name="elementName">The name of the element.</param>
public BsonElementAttribute(string elementName)
{
View
9 Bson/Serialization/BsonClassMap.cs
@@ -1085,7 +1085,10 @@ private BsonMemberMap AutoMapMember(MemberInfo memberInfo)
var elementAttribute = attribute as BsonElementAttribute;
if (elementAttribute != null)
{
- memberMap.SetElementName(elementAttribute.ElementName);
+ if (!string.IsNullOrEmpty(elementAttribute.ElementName))
+ {
+ memberMap.SetElementName(elementAttribute.ElementName);
+ }
memberMap.SetOrder(elementAttribute.Order);
continue;
}
@@ -1191,7 +1194,7 @@ private IEnumerable<MemberInfo> FindMembers()
foreach (var fieldInfo in _classType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
{
var elementAttribute = (BsonElementAttribute)fieldInfo.GetCustomAttributes(typeof(BsonElementAttribute), false).FirstOrDefault();
- if (elementAttribute == null || fieldInfo.IsInitOnly || fieldInfo.IsLiteral)
+ if (elementAttribute == null)
{
continue;
}
@@ -1206,7 +1209,7 @@ private IEnumerable<MemberInfo> FindMembers()
foreach (var propertyInfo in _classType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
{
var elementAttribute = (BsonElementAttribute)propertyInfo.GetCustomAttributes(typeof(BsonElementAttribute), false).FirstOrDefault();
- if (elementAttribute == null || !propertyInfo.CanRead || (!propertyInfo.CanWrite && !_isAnonymous))
+ if (elementAttribute == null)
{
continue;
}
View
11 Bson/Serialization/BsonClassMapSerializer.cs
@@ -142,11 +142,15 @@ public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializ
}
var memberMap = classMap.GetMemberMapForElement(elementName);
- if (memberMap != null && memberMap != classMap.ExtraElementsMemberMap)
+ if (memberMap != null && memberMap != classMap.ExtraElementsMemberMap && !memberMap.IsReadOnly)
{
DeserializeMember(bsonReader, obj, memberMap);
missingElementMemberMaps.Remove(memberMap);
}
+ else if (memberMap != null && memberMap.IsReadOnly)
+ {
+ bsonReader.SkipValue();
+ }
else
{
if (classMap.ExtraElementsMemberMap != null)
@@ -171,6 +175,11 @@ public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializ
foreach (var memberMap in missingElementMemberMaps)
{
+ if (memberMap.IsReadOnly)
+ {
+ continue;
+ }
+
if (memberMap.IsRequired)
{
var fieldOrProperty = (memberMap.MemberInfo.MemberType == MemberTypes.Field) ? "field" : "property";
View
36 Bson/Serialization/BsonMemberMap.cs
@@ -240,6 +240,34 @@ public object DefaultValue
get { return _defaultValue; }
}
+ /// <summary>
+ /// Gets whether the member is readonly.
+ /// </summary>
+ /// <remarks>
+ /// Readonly indicates that the member is written to the database, but not read from the database.
+ /// </remarks>
+ public bool IsReadOnly
+ {
+ get
+ {
+ switch(_memberInfo.MemberType)
+ {
+ case MemberTypes.Field:
+ var field = (FieldInfo)_memberInfo;
+ return field.IsInitOnly || field.IsLiteral;
+ case MemberTypes.Property:
+ var property = (PropertyInfo)_memberInfo;
+ return !property.CanWrite;
+ default:
+ throw new NotSupportedException(
+ string.Format("Only fields and properties are supported by BsonMemberMap. The member {0} of class {1} is a {2}.",
+ _memberInfo.Name,
+ _memberInfo.DeclaringType.Name,
+ _memberInfo.MemberType));
+ }
+ }
+ }
+
// public methods
/// <summary>
/// Applies the default value to the member of an object.
@@ -497,10 +525,10 @@ private static object GetDefaultValue(Type type)
{
var fieldInfo = (FieldInfo)_memberInfo;
- if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral)
+ if (IsReadOnly)
{
var message = string.Format(
- "The field '{0} {1}' of class '{2}' is readonly.",
+ "The field '{0} {1}' of class '{2}' is readonly. To avoid this exception, call IsReadOnly to ensure that setting a value is allowed.",
fieldInfo.FieldType.FullName, fieldInfo.Name, fieldInfo.DeclaringType.FullName);
throw new BsonSerializationException(message);
}
@@ -554,10 +582,10 @@ private static object GetDefaultValue(Type type)
{
var propertyInfo = (PropertyInfo)_memberInfo;
var setMethodInfo = propertyInfo.GetSetMethod(true);
- if (setMethodInfo == null)
+ if (IsReadOnly)
{
var message = string.Format(
- "The property '{0} {1}' of class '{2}' has no 'set' accessor.",
+ "The property '{0} {1}' of class '{2}' has no 'set' accessor. To avoid this exception, call IsReadOnly to ensure that setting a value is allowed.",
propertyInfo.PropertyType.FullName, propertyInfo.Name, propertyInfo.DeclaringType.FullName);
throw new BsonSerializationException(message);
}
View
15 BsonUnitTests/DefaultSerializer/BsonClassMapTests.cs
@@ -40,6 +40,8 @@ private class A
public int FieldMapped;
[BsonElement("FieldMappedByAttribute")]
private int fieldMappedByAttribute;
+ [BsonElement]
+ private readonly int fieldMappedByAttribute2;
public int PropertyMapped { get; set; }
public int PropertyMapped2 { get; private set; }
@@ -49,6 +51,17 @@ private class A
[BsonElement("PropertyMappedByAttribute")]
private int PropertyMappedByAttribute { get; set; }
+
+ [BsonElement]
+ public int PropertyMappedByAttribute2
+ {
+ get { return PropertyMapped + 1; }
+ }
+
+ public A()
+ {
+ fieldMappedByAttribute2 = 10;
+ }
}
#pragma warning restore
@@ -56,7 +69,7 @@ private class A
public void TestMappingPicksUpAllMembersWithAttributes()
{
var classMap = BsonClassMap.LookupClassMap(typeof(A));
- Assert.AreEqual(6, classMap.AllMemberMaps.Count());
+ Assert.AreEqual(8, classMap.AllMemberMaps.Count());
}
}
View
13 BsonUnitTests/DefaultSerializer/BsonDefaultSerializerTests.cs
@@ -75,6 +75,7 @@ static Employee()
cm.MapProperty(e => e.FirstName).SetElementName("fn");
cm.MapProperty(e => e.LastName).SetElementName("ln");
cm.MapProperty(e => e.DateOfBirth).SetElementName("dob").SetSerializer(new DateOfBirthSerializer());
+ cm.MapProperty(e => e.Age).SetElementName("age");
});
}
@@ -82,6 +83,18 @@ static Employee()
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
+ public int Age
+ {
+ get
+ {
+ DateTime now = DateTime.Today;
+ int age = now.Year - DateOfBirth.Year;
+ if (DateOfBirth > now.AddYears(-age))
+ age--;
+
+ return age;
+ }
+ }
}
[Test]
View
138 BsonUnitTests/DefaultSerializer/BsonMemberMapTests.cs
@@ -31,15 +31,23 @@ public class BsonMemberMapTests
{
private class TestClass
{
+ public readonly int ReadOnlyField;
+
public int Field;
public int Property { get; set; }
- public int ReadOnlyProperty { get; private set; }
+ public int PrivateSettableProperty { get; private set; }
+
+ public int ReadOnlyProperty
+ {
+ get { return Property + 1; }
+ }
public TestClass()
{
- ReadOnlyProperty = 10;
+ ReadOnlyField = 13;
+ PrivateSettableProperty = 10;
}
}
@@ -56,6 +64,15 @@ public void TestGettingAField()
}
[Test]
+ public void TestIsReadOnlyPropertyOfAField()
+ {
+ var classMap = new BsonClassMap<TestClass>(cm => cm.AutoMap());
+ var memberMap = classMap.GetMemberMap("Field");
+
+ Assert.IsFalse(memberMap.IsReadOnly);
+ }
+
+ [Test]
public void TestSettingAField()
{
var instance = new TestClass();
@@ -68,6 +85,50 @@ public void TestSettingAField()
}
[Test]
+ public void TestGettingAReadOnlyField()
+ {
+ var instance = new TestClass();
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyField);
+ });
+ var memberMap = classMap.GetMemberMap("ReadOnlyField");
+
+ int value = (int)memberMap.Getter(instance);
+
+ Assert.AreEqual(13, value);
+ }
+
+ [Test]
+ public void TestIsReadOnlyPropertyOfAReadOnlyField()
+ {
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyField);
+ });
+ var memberMap = classMap.GetMemberMap("ReadOnlyField");
+
+ Assert.IsTrue(memberMap.IsReadOnly);
+ }
+
+ [Test]
+ [ExpectedException(typeof(BsonSerializationException), ExpectedMessage = "The field 'System.Int32 ReadOnlyField' of class 'MongoDB.BsonUnitTests.Serialization.BsonMemberMapTests+TestClass' is readonly. To avoid this exception, call IsReadOnly to ensure that setting a value is allowed.")]
+ public void TestSettingAReadOnlyField()
+ {
+ var instance = new TestClass();
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyField);
+ });
+ var memberMap = classMap.GetMemberMap("ReadOnlyField");
+
+ memberMap.Setter(instance, 12);
+ }
+
+ [Test]
public void TestGettingAProperty()
{
var instance = new TestClass { Property = 42 };
@@ -80,6 +141,15 @@ public void TestGettingAProperty()
}
[Test]
+ public void TestIsReadOnlyPropertyOfAProperty()
+ {
+ var classMap = new BsonClassMap<TestClass>(cm => cm.AutoMap());
+ var memberMap = classMap.GetMemberMap("Property");
+
+ Assert.IsFalse(memberMap.IsReadOnly);
+ }
+
+ [Test]
public void TestSettingAProperty()
{
var instance = new TestClass();
@@ -92,11 +162,11 @@ public void TestSettingAProperty()
}
[Test]
- public void TestGettingAReadOnlyProperty()
+ public void TestGettingAPrivateSettableProperty()
{
var instance = new TestClass();
var classMap = new BsonClassMap<TestClass>(cm => cm.AutoMap());
- var memberMap = classMap.GetMemberMap("ReadOnlyProperty");
+ var memberMap = classMap.GetMemberMap("PrivateSettableProperty");
int value = (int)memberMap.Getter(instance);
@@ -104,15 +174,69 @@ public void TestGettingAReadOnlyProperty()
}
[Test]
- public void TestSettingAReadOnlyProperty()
+ public void TestIsReadOnlyPropertyOfAPrivateSettableProperty()
+ {
+ var classMap = new BsonClassMap<TestClass>(cm => cm.AutoMap());
+ var memberMap = classMap.GetMemberMap("PrivateSettableProperty");
+
+ Assert.IsFalse(memberMap.IsReadOnly);
+ }
+
+ [Test]
+ public void TestSettingAPrivateSettableProperty()
{
var instance = new TestClass();
var classMap = new BsonClassMap<TestClass>(cm => cm.AutoMap());
- var memberMap = classMap.GetMemberMap("ReadOnlyProperty");
+ var memberMap = classMap.GetMemberMap("PrivateSettableProperty");
memberMap.Setter(instance, 42);
- Assert.AreEqual(42, instance.ReadOnlyProperty);
+ Assert.AreEqual(42, instance.PrivateSettableProperty);
+ }
+
+ [Test]
+ public void TestGettingAReadOnlyProperty()
+ {
+ var instance = new TestClass { Property = 10 };
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyProperty);
+ });
+
+ var memberMap = classMap.GetMemberMap("ReadOnlyProperty");
+
+ int value = (int)memberMap.Getter(instance);
+
+ Assert.AreEqual(11, value);
+ }
+
+ [Test]
+ public void TestIsReadOnlyPropertyOfAReadOnlyProperty()
+ {
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyProperty);
+ });
+ var memberMap = classMap.GetMemberMap("ReadOnlyProperty");
+
+ Assert.IsTrue(memberMap.IsReadOnly);
+ }
+
+ [Test]
+ [ExpectedException(typeof(BsonSerializationException), ExpectedMessage = "The property 'System.Int32 ReadOnlyProperty' of class 'MongoDB.BsonUnitTests.Serialization.BsonMemberMapTests+TestClass' has no 'set' accessor. To avoid this exception, call IsReadOnly to ensure that setting a value is allowed.")]
+ public void TestSettingAReadOnlyProperty()
+ {
+ var instance = new TestClass { Property = 10 };
+ var classMap = new BsonClassMap<TestClass>(cm =>
+ {
+ cm.AutoMap();
+ cm.MapMember(c => c.ReadOnlyProperty);
+ });
+ var memberMap = classMap.GetMemberMap("ReadOnlyProperty");
+
+ memberMap.Setter(instance, 12);
}
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.