From f78f5db83a3c296cf159847bb4ff0e469e01f415 Mon Sep 17 00:00:00 2001
From: "Santiago M. Mola" <santiago.mola@bitsnbrains.net>
Date: Thu, 5 Apr 2012 13:23:19 +0200
Subject: [PATCH] Add SetGetterFilter and SetSetterFilter to BsonMemberMap.

* GetterFilter is applied before serialization.
* SetterFilter is applied after deserialization.

This allows to hook in the serialization process to introduce
sanitization, escaping/unescaping, etc.
---
 Bson/Serialization/BsonClassMapSerializer.cs       |   13 ++++-
 Bson/Serialization/BsonMemberMap.cs                |   41 ++++++++++++
 BsonUnitTests/BsonUnitTests.csproj                 |    9 +--
 .../Serialization/GetterSetterFiltersTests.cs      |   69 ++++++++++++++++++++
 4 files changed, 126 insertions(+), 6 deletions(-)
 create mode 100644 BsonUnitTests/Serialization/GetterSetterFiltersTests.cs

diff --git a/Bson/Serialization/BsonClassMapSerializer.cs b/Bson/Serialization/BsonClassMapSerializer.cs
index e3fe719..fffe419 100755
--- a/Bson/Serialization/BsonClassMapSerializer.cs
+++ b/Bson/Serialization/BsonClassMapSerializer.cs
@@ -436,6 +436,12 @@ namespace MongoDB.Bson.Serialization
                 }
                 var serializer = memberMap.GetSerializer(actualType);
                 var value = serializer.Deserialize(bsonReader, nominalType, actualType, memberMap.SerializationOptions);
+				
+				if (memberMap.SetterFilter != null)
+				{
+					value = memberMap.SetterFilter(value);
+				}
+				
                 memberMap.Setter(obj, value);
             }
             catch (Exception ex)
@@ -489,7 +495,12 @@ namespace MongoDB.Bson.Serialization
             {
                 return; // don't serialize member
             }
-
+			
+			if (memberMap.GetterFilter != null)
+			{
+				value = memberMap.GetterFilter(value);
+			}
+			
             bsonWriter.WriteName(memberMap.ElementName);
             var nominalType = memberMap.MemberType;
             var actualType = (value == null) ? nominalType : value.GetType();
diff --git a/Bson/Serialization/BsonMemberMap.cs b/Bson/Serialization/BsonMemberMap.cs
index a94db42..b0b308d 100755
--- a/Bson/Serialization/BsonMemberMap.cs
+++ b/Bson/Serialization/BsonMemberMap.cs
@@ -135,6 +135,11 @@ namespace MongoDB.Bson.Serialization
                 return _getter;
             }
         }
+		
+		/// <summary>
+        /// Gets the getter filter function.
+        /// </summary>
+        public Func<object, object> GetterFilter { get; set; }
 
         /// <summary>
         /// Gets the serialization options.
@@ -165,6 +170,11 @@ namespace MongoDB.Bson.Serialization
                 return _setter;
             }
         }
+		
+		/// <summary>
+        /// Gets the setter function.
+        /// </summary>
+        public Func<object, object> SetterFilter { get; set; }
 
         /// <summary>
         /// Gets the Id generator.
@@ -302,6 +312,21 @@ namespace MongoDB.Bson.Serialization
             _elementName = elementName;
             return this;
         }
+		
+		/// <summary>
+		/// Sets the getter filter.
+		/// </summary>
+		/// <param name='filter'>
+		/// The getter filter.
+		/// </param>
+		/// <returns>
+		/// The member map.
+		/// </returns>
+		public BsonMemberMap SetGetterFilter(Func<object, object> filter)
+		{
+			GetterFilter = filter;
+			return this;
+		}
 
         /// <summary>
         /// Sets the Id generator.
@@ -410,6 +435,22 @@ namespace MongoDB.Bson.Serialization
             _ignoreIfDefault = !serializeDefaultValue;
             return this;
         }
+		
+		/// <summary>
+		/// Sets the setter filter.
+		/// </summary>
+		/// <param name='filter'>
+		/// The setter filter.
+		/// </param>
+		/// <returns>
+		/// The member map.
+		/// </returns>
+		public BsonMemberMap SetSetterFilter(Func<object, object> filter)
+		{
+			SetterFilter = filter;
+			return this;
+		}
+
 
         /// <summary>
         /// Sets the method that will be called to determine whether the member should be serialized.
diff --git a/BsonUnitTests/BsonUnitTests.csproj b/BsonUnitTests/BsonUnitTests.csproj
index 04620e9..144b1b8 100644
--- a/BsonUnitTests/BsonUnitTests.csproj
+++ b/BsonUnitTests/BsonUnitTests.csproj
@@ -1,4 +1,4 @@
-﻿<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -68,10 +68,8 @@
     </Reference>
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
-    <Reference Include="WindowsBase">
-    </Reference>
-    <Reference Include="nunit.framework, Version=2.5.9.10348, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="WindowsBase" />
+    <Reference Include="nunit.framework">
       <HintPath>..\dependencies\NUnit\lib\nunit.framework.dll</HintPath>
     </Reference>
   </ItemGroup>
@@ -177,6 +175,7 @@
     <Compile Include="DefaultSerializer\Serializers\BsonPrimitiveSerializerTests.cs" />
     <Compile Include="DefaultSerializer\SerializeInterfaceTests.cs" />
     <Compile Include="Serialization\IdGeneratorsTests.cs" />
+    <Compile Include="Serialization\GetterSetterFiltersTests.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Bson\Bson.csproj">
diff --git a/BsonUnitTests/Serialization/GetterSetterFiltersTests.cs b/BsonUnitTests/Serialization/GetterSetterFiltersTests.cs
new file mode 100644
index 0000000..9ef5948
--- /dev/null
+++ b/BsonUnitTests/Serialization/GetterSetterFiltersTests.cs
@@ -0,0 +1,69 @@
+﻿/* Copyright 2010-2012 10gen 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.IdGenerators;
+
+namespace MongoDB.BsonUnitTests.Serialization
+{
+    [TestFixture]
+    public class TestGetterSetterFilters
+    {
+        private class TestClass {
+			public string Property { get; set; }
+		}
+		
+        [Test]
+        public void TestGetterSetterFilter()
+        {
+			BsonClassMap.RegisterClassMap<TestClass>(cm => {
+				cm.AutoMap();
+				cm.GetMemberMap(c => c.Property)
+					.SetGetterFilter(delegate(object v)
+					{
+						var str = (string)v;
+						return str.ToLower();
+					})
+					.SetSetterFilter(delegate(object v)
+					{
+						var str = (string)v;
+						return str.ToUpper();
+					});
+			});
+			
+			var testObj = new TestClass();
+			testObj.Property = "FOO";
+			
+			var doc = new BsonDocument();
+			var writer = BsonWriter.Create(doc);
+			
+			BsonSerializer.Serialize(writer, testObj);
+			Assert.AreEqual("foo", doc["Property"].AsString);
+
+			testObj = (TestClass)BsonSerializer.Deserialize(doc, typeof(TestClass));
+			Assert.AreEqual("FOO", testObj.Property);
+			
+        }
+
+    }
+}
-- 
1.7.5.4

