-Added support for BindToName on SerializationBinder

This commit is contained in:
JamesNK
2011-07-28 00:53:50 +00:00
parent 588e90a11f
commit 8f01fa44f5
11 changed files with 230 additions and 18 deletions
@@ -125,10 +125,13 @@
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
<Compile Include="Serialization\ContractResolverTests.cs" />
<Compile Include="Serialization\DefaultValueHandlingTests.cs" />
<Compile Include="Serialization\DynamicTests.cs" />
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
<Compile Include="Serialization\JsonSerializerTest.cs" />
<Compile Include="Serialization\MissingMemberHandlingTests.cs" />
<Compile Include="Serialization\NullValueHandlingTests.cs" />
<Compile Include="Serialization\PopulateTests.cs" />
<Compile Include="Serialization\PreserveReferencesHandlingTests.cs" />
<Compile Include="Serialization\SerializationErrorHandlingTests.cs" />
@@ -88,9 +88,13 @@
<Compile Include="Schema\JsonSchemaNodeTests.cs" />
<Compile Include="Serialization\CamelCasePropertyNamesContractResolverTests.cs" />
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
<Compile Include="Serialization\ContractResolverTests.cs" />
<Compile Include="Serialization\DefaultValueHandlingTests.cs" />
<Compile Include="Serialization\DynamicTests.cs" />
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
<Compile Include="Serialization\JsonSerializerTest.cs" />
<Compile Include="Serialization\MissingMemberHandlingTests.cs" />
<Compile Include="Serialization\NullValueHandlingTests.cs" />
<Compile Include="Serialization\PopulateTests.cs" />
<Compile Include="Serialization\PreserveReferencesHandlingTests.cs" />
<Compile Include="Serialization\SerializationErrorHandlingTests.cs" />
@@ -41,5 +41,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.2.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.0.2.13904")]
[assembly: AssemblyFileVersion("4.0.2.13928")]
#endif
@@ -1,4 +1,4 @@
#if !(NET35 || NET20)
#if !(NET35 || NET20 || WINDOWS_PHONE)
using System;
using System.Collections;
using System.Collections.Generic;
@@ -4511,5 +4511,98 @@ keyword such as type of business.""
Assert.AreEqual(1, c2.Categories["one"]);
Assert.AreEqual(2, c2.Categories["two"]);
}
[JsonObject(MemberSerialization.OptIn)]
public class ClassAttributeBase
{
[JsonProperty]
public string BaseClassValue { get; set; }
}
public class ClassAttributeDerived : ClassAttributeBase
{
[JsonProperty]
public string DerivedClassValue { get; set; }
public string NonSerialized { get; set; }
}
public class CollectionClassAttributeDerived : ClassAttributeBase, ICollection<object>
{
[JsonProperty]
public string CollectionDerivedClassValue { get; set; }
public void Add(object item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(object item)
{
throw new NotImplementedException();
}
public void CopyTo(object[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public int Count
{
get { throw new NotImplementedException(); }
}
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
public bool Remove(object item)
{
throw new NotImplementedException();
}
public IEnumerator<object> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
[Test]
public void ClassAttributesInheritance()
{
string json = JsonConvert.SerializeObject(new ClassAttributeDerived
{
BaseClassValue = "BaseClassValue!",
DerivedClassValue = "DerivedClassValue!",
NonSerialized = "NonSerialized!"
}, Formatting.Indented);
Assert.AreEqual(@"{
""DerivedClassValue"": ""DerivedClassValue!"",
""BaseClassValue"": ""BaseClassValue!""
}", json);
json = JsonConvert.SerializeObject(new CollectionClassAttributeDerived
{
BaseClassValue = "BaseClassValue!",
CollectionDerivedClassValue = "CollectionDerivedClassValue!"
}, Formatting.Indented);
Assert.AreEqual(@"{
""CollectionDerivedClassValue"": ""CollectionDerivedClassValue!"",
""BaseClassValue"": ""BaseClassValue!""
}", json);
}
}
}
@@ -430,7 +430,6 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(5, nested[4]);
}
#if !SILVERLIGHT && !PocketPC
[Test]
public void DeserializeUsingCustomBinder()
{
@@ -460,6 +459,89 @@ namespace Newtonsoft.Json.Tests.Serialization
return typeof (Person);
}
}
#if !(NET20 || NET35)
[Test]
public void SerializeUsingCustomBinder()
{
IList<object> values = new List<object>
{
new Person
{
BirthDate = new DateTime(2000, 10, 23, 1, 1, 1, DateTimeKind.Utc),
LastModified = new DateTime(2000, 10, 23, 1, 1, 1, DateTimeKind.Utc),
Name = "Name!",
Department = "Department!"
},
new Employee
{
BirthDate = new DateTime(2000, 10, 23, 1, 1, 1, DateTimeKind.Utc),
FirstName = "FirstName!",
LastName = "LastName!",
Department = "Department!",
JobTitle = "JobTitle!"
}
};
string json = JsonConvert.SerializeObject(values, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = new CompleteSerializationBinder()
});
Assert.AreEqual(@"[
{
""$type"": ""Person"",
""Name"": ""Name!"",
""BirthDate"": ""\/Date(972262861000)\/"",
""LastModified"": ""\/Date(972262861000)\/""
},
{
""$type"": ""Employee"",
""FirstName"": ""FirstName!"",
""LastName"": ""LastName!"",
""BirthDate"": ""\/Date(972262861000)\/"",
""Department"": ""Department!"",
""JobTitle"": ""JobTitle!""
}
]", json);
IList<object> newValues = JsonConvert.DeserializeObject<IList<object>>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = new CompleteSerializationBinder()
});
Assert.IsInstanceOfType(typeof(Person), newValues[0]);
Person person = (Person)newValues[0];
Assert.AreEqual("Name!", person.Name);
Assert.IsInstanceOfType(typeof(Employee), newValues[1]);
Employee employee = (Employee)newValues[1];
Assert.AreEqual("FirstName!", employee.FirstName);
}
public class CompleteSerializationBinder : SerializationBinder
{
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
public override Type BindToType(string assemblyName, string typeName)
{
switch (typeName)
{
case "Employee":
return typeof (Employee);
case "Person":
return typeof (Person);
default:
throw new ArgumentException();
}
}
}
#endif
[Test]
@@ -110,7 +110,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.2.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.0.2.13904")]
[assembly: AssemblyFileVersion("4.0.2.13928")]
#endif
[assembly: CLSCompliant(true)]
@@ -116,5 +116,18 @@ namespace Newtonsoft.Json.Serialization
{
return _typeCache.Get(new TypeNameKey(assemblyName, typeName));
}
#if !(NET35 || NET20)
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
#if !SILVERLIGHT
assemblyName = serializedType.Assembly.FullName;
typeName = serializedType.FullName;
#else
assemblyName = null;
typeName = serializedType.AssemblyQualifiedName;
#endif
}
#endif
}
}
@@ -357,7 +357,7 @@ namespace Newtonsoft.Json.Serialization
private void WriteTypeProperty(JsonWriter writer, Type type)
{
writer.WritePropertyName(JsonTypeReflector.TypePropertyName);
writer.WriteValue(ReflectionUtils.GetTypeName(type, Serializer.TypeNameAssemblyFormat));
writer.WriteValue(ReflectionUtils.GetTypeName(type, Serializer.TypeNameAssemblyFormat, Serializer.Binder));
}
private bool HasFlag(PreserveReferencesHandling value, PreserveReferencesHandling flag)
@@ -16,6 +16,12 @@ namespace Newtonsoft.Json
/// <param name="typeName">Specifies the <see cref="Type"/> name of the serialized object</param>
/// <returns></returns>
public abstract Type BindToType(string assemblyName, string typeName);
public virtual void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = null;
}
}
}
#endif
@@ -29,6 +29,7 @@ using System.Reflection;
using System.Collections;
using System.Linq;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Text.RegularExpressions;
@@ -59,10 +60,31 @@ namespace Newtonsoft.Json.Utilities
public static string GetTypeName(Type t, FormatterAssemblyStyle assemblyFormat)
{
return GetTypeName(t, assemblyFormat, null);
}
public static string GetTypeName(Type t, FormatterAssemblyStyle assemblyFormat, SerializationBinder binder)
{
string fullyQualifiedTypeName;
#if !(NET20 || NET35)
if (binder != null)
{
string assemblyName, typeName;
binder.BindToName(t, out assemblyName, out typeName);
fullyQualifiedTypeName = typeName + (assemblyName == null ? "" : ", " + assemblyName);
}
else
{
fullyQualifiedTypeName = t.AssemblyQualifiedName;
}
#else
fullyQualifiedTypeName = t.AssemblyQualifiedName;
#endif
switch (assemblyFormat)
{
case FormatterAssemblyStyle.Simple:
return GetSimpleTypeName(t);
return RemoveAssemblyDetails(fullyQualifiedTypeName);
case FormatterAssemblyStyle.Full:
return t.AssemblyQualifiedName;
default:
@@ -70,19 +92,8 @@ namespace Newtonsoft.Json.Utilities
}
}
private static string GetSimpleTypeName(Type type)
private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
{
#if !SILVERLIGHT
string fullyQualifiedTypeName = type.FullName + ", " + type.Assembly.GetName().Name;
// for type names with no nested type names then return
if (!type.IsGenericType || type.IsGenericTypeDefinition)
return fullyQualifiedTypeName;
#else
// Assembly.GetName() is marked SecurityCritical
string fullyQualifiedTypeName = type.AssemblyQualifiedName;
#endif
StringBuilder builder = new StringBuilder();
// loop through the type name and filter out qualified assembly details from nested type names