-Added support for overriding the creation of non-concrete types
This commit is contained in:
@@ -235,6 +235,7 @@
|
||||
<Compile Include="Serialization\ConstructorHandlingTests.cs" />
|
||||
<Compile Include="Serialization\ContractResolverTests.cs" />
|
||||
<Compile Include="Serialization\DefaultValueHandlingTests.cs" />
|
||||
<Compile Include="Serialization\DynamicConcreteTests.cs" />
|
||||
<Compile Include="Serialization\DynamicTests.cs" />
|
||||
<Compile Include="Serialization\EntitiesSerializationTests.cs" />
|
||||
<Compile Include="Serialization\ExtensionDataTests.cs" />
|
||||
|
||||
@@ -108,6 +108,155 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[TestFixture]
|
||||
public class ContractResolverTests : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void ListInterface()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonArrayContract)resolver.ResolveContract(typeof(IList<int>));
|
||||
|
||||
Assert.IsTrue(contract.IsInstantiable);
|
||||
Assert.AreEqual(typeof(List<int>), contract.CreatedType);
|
||||
Assert.IsNotNull(contract.DefaultCreator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AbstractTestClass()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonObjectContract)resolver.ResolveContract(typeof(AbstractTestClass));
|
||||
|
||||
Assert.IsFalse(contract.IsInstantiable);
|
||||
Assert.IsNull(contract.DefaultCreator);
|
||||
Assert.IsNull(contract.OverrideCreator);
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractTestClass. Type is an interface or abstract class and cannot be instantiated. Path 'Value', line 1, position 7.",
|
||||
() => JsonConvert.DeserializeObject<AbstractTestClass>(@"{Value:'Value!'}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
}));
|
||||
|
||||
contract.DefaultCreator = () => new AbstractImplementationTestClass();
|
||||
|
||||
var o = JsonConvert.DeserializeObject<AbstractTestClass>(@"{Value:'Value!'}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual("Value!", o.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AbstractListTestClass()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonArrayContract)resolver.ResolveContract(typeof(AbstractListTestClass<int>));
|
||||
|
||||
Assert.IsFalse(contract.IsInstantiable);
|
||||
Assert.IsNull(contract.DefaultCreator);
|
||||
Assert.IsNull(contract.ParametrizedCreator);
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractListTestClass`1[System.Int32]. Type is an interface or abstract class and cannot be instantiated. Path '', line 1, position 1.",
|
||||
() => JsonConvert.DeserializeObject<AbstractListTestClass<int>>(@"[1,2]", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
}));
|
||||
|
||||
contract.DefaultCreator = () => new AbstractImplementationListTestClass<int>();
|
||||
|
||||
var l = JsonConvert.DeserializeObject<AbstractListTestClass<int>>(@"[1,2]", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual(2, l.Count);
|
||||
Assert.AreEqual(1, l[0]);
|
||||
Assert.AreEqual(2, l[1]);
|
||||
}
|
||||
|
||||
public class CustomList<T> : List<T>
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ListInterfaceDefaultCreator()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonArrayContract)resolver.ResolveContract(typeof(IList<int>));
|
||||
|
||||
Assert.IsTrue(contract.IsInstantiable);
|
||||
Assert.IsNotNull(contract.DefaultCreator);
|
||||
|
||||
contract.DefaultCreator = () => new CustomList<int>();
|
||||
|
||||
var l = JsonConvert.DeserializeObject<IList<int>>(@"[1,2,3]", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual(typeof(CustomList<int>), l.GetType());
|
||||
Assert.AreEqual(3, l.Count);
|
||||
Assert.AreEqual(1, l[0]);
|
||||
Assert.AreEqual(2, l[1]);
|
||||
Assert.AreEqual(3, l[2]);
|
||||
}
|
||||
|
||||
public class CustomDictionary<TKey, TValue> : Dictionary<TKey, TValue>
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DictionaryInterfaceDefaultCreator()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonDictionaryContract)resolver.ResolveContract(typeof(IDictionary<string, int>));
|
||||
|
||||
Assert.IsTrue(contract.IsInstantiable);
|
||||
Assert.IsNotNull(contract.DefaultCreator);
|
||||
|
||||
contract.DefaultCreator = () => new CustomDictionary<string, int>();
|
||||
|
||||
var d = JsonConvert.DeserializeObject<IDictionary<string, int>>(@"{key1:1,key2:2}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual(typeof(CustomDictionary<string, int>), d.GetType());
|
||||
Assert.AreEqual(2, d.Count);
|
||||
Assert.AreEqual(1, d["key1"]);
|
||||
Assert.AreEqual(2, d["key2"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AbstractDictionaryTestClass()
|
||||
{
|
||||
var resolver = new DefaultContractResolver();
|
||||
var contract = (JsonDictionaryContract)resolver.ResolveContract(typeof(AbstractDictionaryTestClass<string, int>));
|
||||
|
||||
Assert.IsFalse(contract.IsInstantiable);
|
||||
Assert.IsNull(contract.DefaultCreator);
|
||||
Assert.IsNull(contract.ParametrizedCreator);
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Could not create an instance of type Newtonsoft.Json.Tests.Serialization.AbstractDictionaryTestClass`2[System.String,System.Int32]. Type is an interface or abstract class and cannot be instantiated. Path 'key1', line 1, position 6.",
|
||||
() => JsonConvert.DeserializeObject<AbstractDictionaryTestClass<string, int>>(@"{key1:1,key2:2}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
}));
|
||||
|
||||
contract.DefaultCreator = () => new AbstractImplementationDictionaryTestClass<string, int>();
|
||||
|
||||
var d = JsonConvert.DeserializeObject<AbstractDictionaryTestClass<string, int>>(@"{key1:1,key2:2}", new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = resolver
|
||||
});
|
||||
|
||||
Assert.AreEqual(2, d.Count);
|
||||
Assert.AreEqual(1, d["key1"]);
|
||||
Assert.AreEqual(2, d["key2"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeWithEscapedPropertyName()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
#if !NETFX_CORE
|
||||
using NUnit.Framework;
|
||||
#else
|
||||
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
|
||||
using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
|
||||
using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Serialization
|
||||
{
|
||||
[TestFixture]
|
||||
public class DynamicConcreteTests : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void UseDynamicConcreteIfTargetObjectTypeIsAnInterfaceWithNoBackingClass()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
var c = JsonConvert.DeserializeObject<IInterfaceWithNoConcrete>(json, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DynamicConcreteContractResolver()
|
||||
});
|
||||
|
||||
Assert.AreEqual("Name!", c.Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UseDynamicConcreteIfTargetObjectTypeIsAnAbstractClassWithNoConcrete()
|
||||
{
|
||||
string json = @"{Name:""Name!"", Game:""Same""}";
|
||||
|
||||
var c = JsonConvert.DeserializeObject<AbstractWithNoConcrete>(json, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DynamicConcreteContractResolver()
|
||||
});
|
||||
|
||||
Assert.AreEqual("Name!", c.Name);
|
||||
Assert.AreEqual("Same", c.Game);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnyMethodsExposedByDynamicConcreteAreHarmless()
|
||||
{
|
||||
string json = @"{Name:""Name!""}";
|
||||
|
||||
var c = JsonConvert.DeserializeObject<IInterfaceWithNoConcrete>(json, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DynamicConcreteContractResolver()
|
||||
});
|
||||
|
||||
c.FuncWithRefType(10, null);
|
||||
c.FuncWithValType_1();
|
||||
c.FuncWithValType_2();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AbstractWithNoConcrete
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public abstract string Game { get; set; }
|
||||
}
|
||||
|
||||
public interface IInterfaceWithNoConcrete
|
||||
{
|
||||
string Name { get; set; }
|
||||
object FuncWithRefType(int a, object b);
|
||||
int FuncWithValType_1();
|
||||
bool FuncWithValType_2();
|
||||
}
|
||||
|
||||
public class DynamicConcreteContractResolver : DefaultContractResolver
|
||||
{
|
||||
protected override JsonContract CreateContract(Type objectType)
|
||||
{
|
||||
JsonContract contract = base.CreateContract(objectType);
|
||||
if (contract.CreatedType.IsAbstract || contract.CreatedType.IsInterface)
|
||||
contract.DefaultCreator = () => DynamicConcrete.GetInstanceFor(contract.CreatedType);
|
||||
|
||||
return contract;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates run-time backing types for abstract classes and interfaces
|
||||
/// </summary>
|
||||
public static class DynamicConcrete
|
||||
{
|
||||
/// <summary>
|
||||
/// Get an empty instance of a dynamic proxy for type T.
|
||||
/// All public fields are writable and all properties have both getters and setters.
|
||||
/// </summary>
|
||||
public static T GetInstanceFor<T>()
|
||||
{
|
||||
return (T)GetInstanceFor(typeof(T));
|
||||
}
|
||||
|
||||
static readonly ModuleBuilder ModuleBuilder;
|
||||
static readonly AssemblyBuilder DynamicAssembly;
|
||||
|
||||
/// <summary>
|
||||
/// Get an empty instance of a dynamic proxy for the given type.
|
||||
/// All public fields are writable and all properties have both getters and setters.
|
||||
/// </summary>
|
||||
public static object GetInstanceFor(Type targetType)
|
||||
{
|
||||
lock (DynamicAssembly)
|
||||
{
|
||||
var constructedType = DynamicAssembly.GetType(ProxyName(targetType)) ?? GetConstructedType(targetType);
|
||||
var instance = Activator.CreateInstance(constructedType);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
static string ProxyName(Type targetType)
|
||||
{
|
||||
return targetType.Name + "Proxy";
|
||||
}
|
||||
|
||||
static DynamicConcrete()
|
||||
{
|
||||
var assemblyName = new AssemblyName("DynImpl");
|
||||
DynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
|
||||
ModuleBuilder = DynamicAssembly.DefineDynamicModule("DynImplModule");
|
||||
}
|
||||
|
||||
static Type GetConstructedType(Type targetType)
|
||||
{
|
||||
var typeBuilder = ModuleBuilder.DefineType(targetType.Name + "Proxy", TypeAttributes.Public);
|
||||
|
||||
var ctorBuilder = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
new Type[] { });
|
||||
var ilGenerator = ctorBuilder.GetILGenerator();
|
||||
ilGenerator.Emit(OpCodes.Ret);
|
||||
|
||||
IncludeType(targetType, typeBuilder);
|
||||
|
||||
foreach (var face in targetType.GetInterfaces())
|
||||
IncludeType(face, typeBuilder);
|
||||
|
||||
return typeBuilder.CreateType();
|
||||
}
|
||||
|
||||
static void IncludeType(Type typeOfT, TypeBuilder typeBuilder)
|
||||
{
|
||||
var methodInfos = typeOfT.GetMethods();
|
||||
foreach (var methodInfo in methodInfos)
|
||||
{
|
||||
if (methodInfo.Name.StartsWith("set_")) continue; // we always add a set for a get.
|
||||
|
||||
if (methodInfo.Name.StartsWith("get_"))
|
||||
{
|
||||
BindProperty(typeBuilder, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInfo.IsAbstract) BindMethod(typeBuilder, methodInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeOfT.IsInterface) typeBuilder.AddInterfaceImplementation(typeOfT);
|
||||
else if (typeOfT.IsAbstract) typeBuilder.SetParent(typeOfT);
|
||||
}
|
||||
|
||||
static void BindMethod(TypeBuilder typeBuilder, MethodInfo methodInfo)
|
||||
{
|
||||
var args = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
|
||||
var methodBuilder = typeBuilder.DefineMethod(
|
||||
methodInfo.Name,
|
||||
MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
CallingConventions.HasThis,
|
||||
methodInfo.ReturnType,
|
||||
args
|
||||
);
|
||||
|
||||
var methodILGen = methodBuilder.GetILGenerator();
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
methodILGen.Emit(OpCodes.Ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInfo.ReturnType.IsPrimitive)
|
||||
{
|
||||
methodILGen.Emit(OpCodes.Ldc_I4_0);
|
||||
}
|
||||
else if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum)
|
||||
{
|
||||
var getMethod = typeof(Activator).GetMethod("CreateInstance",
|
||||
new[] { typeof(Type) });
|
||||
var lb = methodILGen.DeclareLocal(methodInfo.ReturnType);
|
||||
if (lb.LocalType != null)
|
||||
{
|
||||
methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);
|
||||
methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
|
||||
methodILGen.Emit(OpCodes.Callvirt, getMethod);
|
||||
methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodILGen.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
methodILGen.Emit(OpCodes.Ret);
|
||||
}
|
||||
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bind a new property into a type builder with getters and setters.
|
||||
/// </summary>
|
||||
public static void BindProperty(TypeBuilder typeBuilder, MethodInfo methodInfo)
|
||||
{
|
||||
// Backing Field
|
||||
var propertyName = methodInfo.Name.Replace("get_", "");
|
||||
var propertyType = methodInfo.ReturnType;
|
||||
var backingField = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
|
||||
|
||||
//Getter
|
||||
var backingGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
|
||||
MethodAttributes.SpecialName | MethodAttributes.Virtual |
|
||||
MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
|
||||
var getIl = backingGet.GetILGenerator();
|
||||
|
||||
getIl.Emit(OpCodes.Ldarg_0);
|
||||
getIl.Emit(OpCodes.Ldfld, backingField);
|
||||
getIl.Emit(OpCodes.Ret);
|
||||
|
||||
|
||||
//Setter
|
||||
var backingSet = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public |
|
||||
MethodAttributes.SpecialName | MethodAttributes.Virtual |
|
||||
MethodAttributes.HideBySig, null, new[] { propertyType });
|
||||
|
||||
var setIl = backingSet.GetILGenerator();
|
||||
|
||||
setIl.Emit(OpCodes.Ldarg_0);
|
||||
setIl.Emit(OpCodes.Ldarg_1);
|
||||
setIl.Emit(OpCodes.Stfld, backingField);
|
||||
setIl.Emit(OpCodes.Ret);
|
||||
|
||||
// Property
|
||||
var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
|
||||
propertyBuilder.SetGetMethod(backingGet);
|
||||
propertyBuilder.SetSetMethod(backingSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7898,6 +7898,31 @@ Parameter name: value",
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AbstractTestClass
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class AbstractImplementationTestClass : AbstractTestClass
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class AbstractListTestClass<T> : List<T>
|
||||
{
|
||||
}
|
||||
|
||||
public class AbstractImplementationListTestClass<T> : AbstractListTestClass<T>
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class AbstractDictionaryTestClass<TKey, TValue> : Dictionary<TKey, TValue>
|
||||
{
|
||||
}
|
||||
|
||||
public class AbstractImplementationDictionaryTestClass<TKey, TValue> : AbstractDictionaryTestClass<TKey, TValue>
|
||||
{
|
||||
}
|
||||
|
||||
public class PublicConstructorOverridenByJsonConstructor
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
@@ -375,34 +375,37 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (attribute != null)
|
||||
contract.ItemRequired = attribute._itemRequired;
|
||||
|
||||
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
|
||||
if (contract.IsInstantiable)
|
||||
{
|
||||
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
|
||||
|
||||
// check if a JsonConstructorAttribute has been defined and use that
|
||||
if (overrideConstructor != null)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
contract.OverrideConstructor = overrideConstructor;
|
||||
#pragma warning restore 618
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
|
||||
}
|
||||
else if (contract.MemberSerialization == MemberSerialization.Fields)
|
||||
{
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
// mimic DataContractSerializer behaviour when populating fields by overriding default creator to create an uninitialized object
|
||||
// note that this is only possible when the application is fully trusted so fall back to using the default constructor (if available) in partial trust
|
||||
if (JsonTypeReflector.FullyTrusted)
|
||||
contract.DefaultCreator = contract.GetUninitializedObject;
|
||||
#endif
|
||||
}
|
||||
else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
|
||||
{
|
||||
ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
|
||||
if (constructor != null)
|
||||
// check if a JsonConstructorAttribute has been defined and use that
|
||||
if (overrideConstructor != null)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
contract.ParametrizedConstructor = constructor;
|
||||
contract.OverrideConstructor = overrideConstructor;
|
||||
#pragma warning restore 618
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties));
|
||||
}
|
||||
else if (contract.MemberSerialization == MemberSerialization.Fields)
|
||||
{
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
// mimic DataContractSerializer behaviour when populating fields by overriding default creator to create an uninitialized object
|
||||
// note that this is only possible when the application is fully trusted so fall back to using the default constructor (if available) in partial trust
|
||||
if (JsonTypeReflector.FullyTrusted)
|
||||
contract.DefaultCreator = contract.GetUninitializedObject;
|
||||
#endif
|
||||
}
|
||||
else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
|
||||
{
|
||||
ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType);
|
||||
if (constructor != null)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
contract.ParametrizedConstructor = constructor;
|
||||
#pragma warning restore 618
|
||||
contract.CreatorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,8 +706,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
// then see whether object is compadible with any of the built in converters
|
||||
contract.InternalConverter = JsonSerializer.GetMatchingConverter(BuiltInConverters, contract.NonNullableUnderlyingType);
|
||||
|
||||
if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
|
||||
|| contract.CreatedType.IsValueType())
|
||||
if (contract.IsInstantiable
|
||||
&& (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true) || contract.CreatedType.IsValueType()))
|
||||
{
|
||||
contract.DefaultCreator = GetDefaultCreator(contract.CreatedType);
|
||||
|
||||
|
||||
@@ -86,12 +86,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
internal bool IsNullable;
|
||||
internal bool IsConvertable;
|
||||
internal bool IsSealed;
|
||||
internal bool IsEnum;
|
||||
internal Type NonNullableUnderlyingType;
|
||||
internal ReadType InternalReadType;
|
||||
internal JsonContractType ContractType;
|
||||
internal bool IsReadOnlyOrFixedSize;
|
||||
internal bool IsSealed;
|
||||
internal bool IsInstantiable;
|
||||
|
||||
private List<SerializationCallback> _onDeserializedCallbacks;
|
||||
@@ -99,6 +99,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
private IList<SerializationCallback> _onSerializedCallbacks;
|
||||
private IList<SerializationCallback> _onSerializingCallbacks;
|
||||
private IList<SerializationErrorCallback> _onErrorCallbacks;
|
||||
private Type _createdType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying type for the contract.
|
||||
@@ -110,7 +111,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// Gets or sets the type created during deserialization.
|
||||
/// </summary>
|
||||
/// <value>The type created during deserialization.</value>
|
||||
public Type CreatedType { get; set; }
|
||||
public Type CreatedType
|
||||
{
|
||||
get { return _createdType; }
|
||||
set
|
||||
{
|
||||
_createdType = value;
|
||||
|
||||
IsSealed = _createdType.IsSealed();
|
||||
IsInstantiable = !(_createdType.IsInterface() || _createdType.IsAbstract());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this type contract is serialized as a reference.
|
||||
@@ -296,9 +307,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
UnderlyingType = underlyingType;
|
||||
|
||||
IsSealed = underlyingType.IsSealed();
|
||||
IsInstantiable = !(underlyingType.IsInterface() || underlyingType.IsAbstract());
|
||||
|
||||
IsNullable = ReflectionUtils.IsNullable(underlyingType);
|
||||
NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType;
|
||||
|
||||
|
||||
@@ -1036,6 +1036,9 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!contract.IsInstantiable)
|
||||
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
}
|
||||
}
|
||||
@@ -1064,6 +1067,9 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!contract.IsInstantiable)
|
||||
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
}
|
||||
}
|
||||
@@ -1825,9 +1831,6 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
{
|
||||
object newObject = null;
|
||||
|
||||
if (!objectContract.IsInstantiable)
|
||||
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
|
||||
|
||||
if (objectContract.OverrideCreator != null)
|
||||
{
|
||||
if (objectContract.CreatorParameters.Count > 0)
|
||||
@@ -1854,7 +1857,12 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}
|
||||
|
||||
if (newObject == null)
|
||||
{
|
||||
if (!objectContract.IsInstantiable)
|
||||
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
|
||||
}
|
||||
|
||||
createdFromNonDefaultCreator = false;
|
||||
return newObject;
|
||||
|
||||
Reference in New Issue
Block a user